MongoDb c# update array in document - c#

I have the following code:
_eventInstanceRepository.GetInnerCollection().Update(
Query.EQ("_id", listingEventModel.Id),
Update.PushWrapped<string[]>("ArtistIds", ids.ToArray()));
Which is designed to update the following document:
public class ListingEvent
{
public ObjectId Id { get; set; }
public string[] ArtistIds { get; set; }
}
ids is a List
Any ideas why this isn't updating the docs?
[UPDATE]
Also tried this!
foreach (var id in ids)
{
_eventInstanceRepository.GetInnerCollection().Update(
Query.EQ("_id", listingEventModel.Id),
Update.Push("ArtistIds", id));
}
No luck...
[UPDATE]
Going back to RavenDb - at least for now. I don't see how MongoDb is a viable option the whole time there are no real sources discussing (slightly more complex than flat structure) document updates on the internet and the examples I can find simply do not work.
[UPDATE]
Here is the repository code:
public class Repository<T> : IRepository<T>
{
private readonly MongoCollection<T> _docs;
public Repository(MongoCollection<T> docs)
{
_docs = docs;
}
public IList<T> GetAll()
{
return _docs.FindAll().Select<T, T>(x => x.As<T>()).ToList();
}
//HACK!
public MongoCollection<T> GetInnerCollection(){
return _docs;
}
public void Save(T doc)
{
_docs.Save(doc);
}
public void Save(IEnumerable<T> docsToSave)
{
foreach (var doc in docsToSave) Save(doc);
}
public void Dispose()
{
throw new NotImplementedException();
}
public void Delete(string id)
{
var query = Query.EQ("_id", id);
_docs.Remove(query);
}
}

Working sample code for appending a list of strings to an existing list of strings using a strongly-typed Push:
class Event
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public List<string> Participants { get; set; }
}
class Program
{
static void Main(string[] args)
{
MongoClient client = new MongoClient("mongodb://localhost/test");
var db = client.GetServer().GetDatabase("test");
var collection = db.GetCollection("events");
var event0 = new Event { Name = "Birthday Party",
Participants = new List<string> { "Jane Fonda" } };
collection.Insert(event0);
collection.Update(Query.EQ("_id", event0.Id),
Update<Event>.PushAll(p => p.Participants,
new List<string> { "John Doe", "Michael Rogers" }));
}
}

Related

Unable to determine the serialization information when create index

I'm having problem when i create a index.
This is my code:
private static IMongoCollection<IPageItem> GetCollection()
{
return Connection.Database.GetCollection<IPageItem>("SystemPages");
}
internal static IEnumerable<Task> CreateIndex()
{
BsonClassMap.RegisterClassMap<NewsItem>();
var work = new List<Task>();
var coll = GetCollection();
var builder= Builders<IPageItem>.IndexKeys;
var btIndexes = new List<CreateIndexModel<IPageItem>>
{
new(builder.Ascending(x => x.PageId), new CreateIndexOptions { Unique = true })
};
work.Add(coll.Indexes.CreateManyAsync(btIndexes));
return work;
}
public interface IPageItem
{
public Guid PageId { get; set; }
}
public class NewsItem : IPageItem
{
public Guid PageId { get; set; }
public string Summery { get; set; }
}
When i call, CreateIndex() i receive, Unable to determine the serialization information for x => Convert(x.PageId, Object).)
Can I not use one interface when create/get a collection?

How to save/write Task with different attributes

I am trying to build a more advanced ToDoList-Console program. I am learning serialisation but what I do not seem to understand is how to:
Implement 2 kinds of tasks
saving them in a file(does not have to be json)
reading the file while taking the task type into consideration
My goal with that is having 2 Methods: task1 and task2. Task1 being the main task and task2 being a subtask of a task, which would be visualised with \t in the console.
This is my current code that just saves tasks as a string, without any kind of complexity.
public class TodoItem
{
public string Description { get; set; }
public DateTime? DueOn { get; set; }
public override string ToString()
{
return $"{this.Description}";
}
}
internal static class Program
{
static private readonly string _saveFileName = "todo.json";
static void Main()
{
{
// An example list containing 2 items
List<TodoItem> items = new List<TodoItem> {
new TodoItem { Description = "Feed the dog" },
new TodoItem { Description = "Buy groceries" /*, DueOn = new DateTime(2021, 9, 30, 16, 0, 0)*/ }
};
// Serialize it to JSON
string json = JsonSerializer.Serialize(items, new JsonSerializerOptions() { WriteIndented = true });
// Save it to a file
File.WriteAllText(_saveFileName, json);
}
// Loading list
{
string json = File.ReadAllText(_saveFileName);
List<TodoItem> items = JsonSerializer.Deserialize<List<TodoItem>>(json);
// Loading items
foreach (var todo in items)
Console.WriteLine(todo);
}
}```
You can use inheritance to implement two types of tasks.
The rest of your goals seem to work already :)
Here is an Example:
public abstract class TaskBase
{
public string Description { get; set; }
public DateTime? DueOn { get; set; }
public override string ToString()
{
return $"{Description}";
}
}
public class MainTask : TaskBase
{
public SubTask? SubTask { get; set; }
public override string ToString()
{
if (SubTask is not null)
{
return $"{Description}{Environment.NewLine}\t{SubTask}";
}
else
{
return base.ToString();
}
}
}
public class SubTask : TaskBase {}
static class Program
{
private const string _saveFileName = "todo.json";
static void Main()
{
{
// An example list containing 2 items
List<MainTask> items = new List<MainTask>
{
new MainTask { Description = "Feed the dog" },
new MainTask { Description = "Buy groceries", SubTask = new SubTask { Description = "Food" } }
};
// Serialize it to JSON
string json = JsonSerializer.Serialize(items, new JsonSerializerOptions() { WriteIndented = true });
// Save it to a file
File.WriteAllText(_saveFileName, json);
}
// Loading list
{
string json = File.ReadAllText(_saveFileName);
List<MainTask> items = JsonSerializer.Deserialize<List<MainTask>>(json);
// Loading items
foreach (var todo in items)
Console.WriteLine(todo);
}
}
}

AutoMapper with static factory methods

What is the best approach for using AutoMapper with value objects with static factory methods:
public class ImmutableDetail
{
public static ImmutableDetail Create(string detail) => new ImmutableDetail(detail);
private ImmutableDetail(string detail)
{
Detail = detail;
}
public string Detail { get;}
}
Where I want to be able to:
var immutableDetails = Mapper.Map<ImmutableDetail>(source);
With below classes:
public class DummySource
{
public string Detail { get; set; }
}
public class ImmutableDetail
{
public static ImmutableDetail Create(string detail) { return new ImmutableDetail(detail); }
private ImmutableDetail(string detail)
{
Detail = detail;
}
public string Detail { get; private set; }
}
you can make a mapping like this:
Mapper.CreateMap<DummySource, ImmutableDetail>().ConstructUsing((DummySource ds) => ImmutableDetail.Create(ds.Detail));
var source = new DummySource { Detail = "Hello" };
var immutableDetails = Mapper.Map<ImmutableDetail>(source);

property accessors for List<T>, and entity framework 6 linq queries

Is it possible to have a (EF6) Linq select statement instantiate a class, such that a property's set accessor is triggered with the values returned from the Linq statement?
I have tried code (similar) to that below, but despite the query returning data, the set's value is an empty list. I am assuming that Linq creates a new instance of MyModel, and then adds the records from the record set.
Is it possible to trigger doSomething() after MyList is fully populated, but from within the scope of MyModel (i.e. not adding a subsequent call after context.SomeEntities.Select(...))?
public class MyModel{
private List<string> _myList;
public List<string> MyList {
get { return _myList; }
set { _myList = value; doSomething(); }
}
private void doSomething() {...}
}
..
context.SomeEntities.Select(x => new MyModel { MyList = x.YourList });
The answer to both of your questions is "Yes." The following worked for me:
class Program
{
static void Main(string[] args)
{
Context context = new Context();
List<MyModel> myModelsList = context.Products.Include("Names").AsEnumerable().Select(x =>
{
MyModel model = new MyModel();
model.MyList = x.Names.Select(pn => pn.Name).ToList();
return model;
}).ToList();
}
static void CreateAndSeedDatabase()
{
Context context = new Context();
Product product1 = new Product() { Names = new List<ProductName> { new ProductName { Name = "1" } } };
Product product2 = new Product() { Names = new List<ProductName> { new ProductName { Name = "2" } } };
context.Products.Add(product1);
context.Products.Add(product2);
context.SaveChanges();
}
}
public class Context : DbContext
{
public Context()
{
Database.SetInitializer<Context>(new CreateDatabaseIfNotExists<Context>());
Database.Initialize(true);
}
public DbSet<Product> Products { get; set; }
public DbSet<ProductName> ProductNames { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public List<ProductName> Names { get; set; }
}
public class ProductName
{
public int ProductNameId { get; set; }
public string Name { get; set; }
}
public class MyModel
{
private List<string> _myList;
public List<string> MyList
{
get { return _myList; }
set { _myList = value; doSomething(); }
}
private void doSomething()
{
Console.WriteLine(_myList[0]);
}
}
}

Why I can not cast?

public abstrct class Item
{
public string Name {get;set;}
}
public class Music : Item
{
public double Price {get;set;}
}
public class Game : Item
{
public string Image {get;set;}
}
public class Inventory
{
private IList<Item> _games;
private IList<Item> _musics;
public Inventory()
{
_games = new List<Item>();
_musics = new List<Item>();
}
public void Add<T>(T item) where T : Item
{
if(typeof(T) == typeof(Game))
{
_game.add(item);
}
if(typeof(T) == typeof(Music))
{
_muisc.add(item);
}
public List<T> GetCollection<T>() where T : Item
{
return (List<T>) _muiscs;
}
class Porgram
{
static void Main(string[] args)
{
Inventory inventory = new Inventory();
var music1 = new Music(){ Name ="aa", Price = 10};
var Music2 = new Music() { Name ="bb", price = 20 };
inventory.add(music1);
inventory.add(music2);
List<Music> myMusics = inventory.GetCollection<Music>();
}
The code will compile but it will throw exception when try to Call Get Collection method.
I am not sure really why? I am guess i am using generic incorrect.
A List<Item> cannot be cast to a List<Music>. While Music is a subclass of Item, generic types do not follow the same inheritance pattern as their collection type. The simplest way to fix your code would be to replace the cast in your GetCollection method with a call to the Linq extension method cast, followed by ToList. That said, I think your entire class could be redesigned to handle this sort of inheritence better.
So, your GetCollection method looks like this:
public List<T> GetCollection<T>() where T : Item
{
return _musics.Cast<T>().ToList();
}
Try this code:
public abstract class Item
{
public string Name { get; set; }
}
public class Music : Item
{
public double Price { get; set; }
}
public class Game : Item
{
public string Image { get; set; }
}
public class Inventory<E> where E : Item
{
private IList<E> _games;
private IList<E> _musics;
public Inventory()
{
_games = new List<E>();
_musics = new List<E>();
}
public void Add(E item)
{
if (typeof(E) == typeof(Game))
{
_games.Add(item);
}
if (typeof(E) == typeof(Music))
{
_musics.Add(item);
}
}
public List<E> GetCollection()
{
return _musics;
}
}
public class Program
{
public static void Main(string[] args)
{
Inventory<Item> inventory = new Inventory<Item>();
var music1 = new Music() { Name = "aa", Price = 10 };
var music2 = new Music() { Name = "bb", Price = 20 };
inventory.Add(music1);
inventory.Add(music2);
List<Item> myMusics = inventory.GetCollection();
}
}
You need to declare your Inventory class to be generic where it takes in a class that extend Item
Also: It looks like you wrote the code, and didn't copy and paste it... I don't know why you did that...
Just modify your GetCollection method as
public List <T> GetCollection<T>() where T :Item
{
if (typeof(T) == typeof(Game))
{
return _games.Cast<T>().ToList();
}
if (typeof(T) == typeof(Music))
{
return _musics.Cast<T>().ToList(); ;
}
return null;
}

Categories

Resources