I'm using on a Xamarin Forms project Realm. I have a class A :
public class A: RealmObject
{
[PrimaryKey]
public string Id { get; set; }
public string Name { get; set; }
public A() : base()
{
Id= Guid.NewGuid().ToString();
Name = $"Unknown_{Id}";
}
}
And a class B which contains a list of A's objects :
public class B: RealmObject
{
[PrimaryKey]
public string Id{ get; set; }
public string Name { get; set; }
public IList<A> AList { get; }
public B() : base()
{
Id= Guid.NewGuid().ToString();
Name = $"Unknown_{Id}";
}
}
The IList Alist contains object which are already saved on Realm and i would like to save them like references.
The issue is that when i try to add on Realm a B object, i get the exception :
Realms.Exceptions.RealmObjectManagedByAnotherRealmException: Cannot start to manage an object with a realm when it's already managed by another realm
This exception appears on the line realm.Add(newB, update: true); in the code bellow
private void AddB(B b)
{
var realm = GetRealmInstance();
using (var trans = realm.BeginWrite())
{
var newB = new B();
newB.Name = b.Name;
newB.Id = b.Id;
foreach (var element in b.AList)
{
newB.Devices.Add(element);
}
realm.Add(newB, update: true);
trans.Commit();
});
OnChanged?.Invoke();
}
I have to precise that all objects in the AList are already saved on Realm.
Thanks in advance.
How about:
var newB = new B();
newB.Name = b.Name;
newB.Id = b.Id;
realm.Add(newB, update: true);
foreach (var element in b.AList)
{
newB.Devices.Add(element);
}
trans.Commit();
Related
I have 3 classes as you can see :
public class car
{
public int Id { set; get; }
public string Name { set; get; }
public List<CarTest> CarTest { get; set; }
public car(string name, int id, List<CarTest> carTests)
{
Id = id;
Name = name;
CarTest = carTests;
}
public car()
{
}
}
public class CarTest
{
public OVTest OV { get; set; }
public string CarOV { get; set; }
}
public class OVTest
{
public string Name { get; set; }
}
I want to edit my value as you can see :
static void Main(string[] args)
{
myctx myc = new myctx();
var cartests = new List<CarTest>();
var cartest = new CarTest();
var OV = new OVTest();
OV.Name = "editedName";
cartest.OV = OV;
cartest.CarOV = "2OV";
cartests.Add(cartest);
var editcar = new car("ee5155fe",2, cartests);
myc.ChangeTracker.TrackGraph(editcar, e =>e.Entry.State = EntityState.Modified);
myc.SaveChanges();
Console.ReadLine();
}
But I get this error :
System.InvalidOperationException: 'The property 'CarTestId' on entity type 'OVTest' is part of a key and so cannot be modified or marked as modified. To change the principal of an existing entity with an identifying foreign key first delete the dependent and invoke 'SaveChanges' then associate the dependent with the new principal.'
This is my config:
public class CarConfig : IEntityTypeConfiguration<car>
{
public void Configure(EntityTypeBuilder<car> builder)
{
builder.OwnsMany(u => u.CarTest);
builder.OwnsMany(u => u.CarTest).OwnsOne(c=>c.OV);
}
}
I'm attempting to create a generic method to enable me to parse a CSV document into an object of my choice.
Everything seems to work ok but the results after executing the csv.GetRecords() method are empty and the inner exception of the response is "Instances of abstract classes cannot be created."
I've also tried using the csv.EnumerateRecords(record); and get the same result.
public class ImportManager
{
[Ignore]
public string FileSeperator { get; set; }
[Ignore]
public string Filename { get; set; }
public IEnumerable<T> ParseFile<T>() where T : class
{
using (var reader = new StreamReader(this.Filename))
using (var csv = new CsvReader(reader))
{
csv.Configuration.Delimiter = this.FileSeperator;
csv.Configuration.HasHeaderRecord = true;
var results = csv.GetRecords<T>();
return results;
}
}
}
public class MyObject : ImportManager
{
public string Field1 { get; set; }
public DateTime Field2 { get; set; }
public int Field3 { get; set; }
public List<MyObject> LoadFile()
{
var response = ParseFile<MyObject>();
return response.ToList<MyObject>();
}
}
MyObject moObjList= new MyObject() { Filename = "MyFileName.txt", FileSeperator = "|" };
var results = moObjList.LoadFile();
Help!
I believe adding ToList() to csv.GetRecords<T>() may solve your issue. GetRecords<T>() does a lazy load. It doesn't attempt to enumerate the records until you call return response.ToList<MyObject>(); at which time the StreamReader is already disposed.
public class ImportManager
{
[Ignore]
public string FileSeperator { get; set; }
[Ignore]
public string Filename { get; set; }
public IEnumerable<T> ParseFile<T>() where T : class
{
using (var reader = new StreamReader(this.Filename))
using (var csv = new CsvReader(reader))
{
csv.Configuration.Delimiter = this.FileSeperator;
csv.Configuration.HasHeaderRecord = true;
var results = csv.GetRecords<T>().ToList();
return results;
}
}
}
I have two classes
public class ClassA
{
public int ID { get; set; }
public string Countries {get;set;}
public string City { get;set; }
}
and
public class ClassB
{
public int ID { get; set; }
public string Countries {get;set;}
public string Village{ get;set; }
}
These two classes are in another class
public class ComponentClass
{
public List<ClassA> classAObj { get; set; }
public List<ClassB> classBObj { get; set; }
}
The data for the ComponentClass is coming from third party where the data for ClassA and ClassB is similar in structure. "City" in ClassA will have data in comma separated values "Manchester,Sydney" etc similarly with Village as well with comma separated values.
Now I am building a customized object at business layer where I am iterating through each property of ComponentClass and extracting information.
Main()
{
ComponentClass[] c = //Data from 3rd party;
foreach(var data in c)
{
Parent p = new Parent();
if(data.classAObj.count > 0)
{
Star s = new Star();
s.Area = "infinite";
s.Color = "red";
List<string> sep = data.City.Split(',').Select(string.Parse).ToList();
foreach(var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s.Values.Add(t);
}
p.Curves.Add(s);
}
if(data.classBObj.count > 0)
{
Star s2 = new Star();
s2.Area = "infinite";
s2.Color = "red";
List<string> sep = data.Village.Split(',').Select(string.Parse).ToList();
foreach(var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s2.Values.Add(t);
}
p.Curves.Add(s);
}
}
}
In the code above , the two if statements are doing exactly the same operation apart from property names "City" and "Village". I want to simplify this by making use of any design pattern possibly strategy pattern which I just know theoretically or any other patterns.
Here is what I have tried :
public abstract class Base
{
public int ID { get; set; }
public string Countries {get;set;}
}
public class ClassA : Base
{
public string City { get;set; }
}
public class ClassB : Base
{
public string Village{ get;set; }
}
I want to make it as a common factory method which will do the looping and build the object for me for avoiding duplication of the code
public void CommonMethod(Base)
{
// How do I differentiate the properties for looping
}
If the goal is to reduce the code repetition, the two statements could be refactored into a single action as follows.
foreach(var data in c)
{
Parent p = new Parent();
Action<string> iAction = iString =>
{
Star s = new Star();
s.Area = "infinite";
s.Color = "red";
List<string> sep = iString.Split(',').Select(string.Parse).ToList();
foreach(var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s.Values.Add(t);
}
p.Curves.Add(s);
}
if(data.classAObj.count > 0)
{
iAction(data.City);
}
if(data.classBObj.count > 0)
{
iAction(data.Village);
}
}
You have a same datatype properties for the both of the types in the json than you can create a single class to map it,
public class ClassA
{
public int ID { get; set; }
public string Countries {get;set;}
public string Areas{ get;set; }
}
public class ComponentClass
{
public List<ClassA> classAObj { get; set; }
public List<ClassA> classBObj { get; set; }
}
Main()
{
ComponentClass[] c = //Data from 3rd party;
foreach(var data in c)
{
Parent p = new Parent();
GetParent (p ,data.classAObj )
GetParent (p ,data.classBObj )
}
}
void GetParent (Parent p, ClassA classObj){
if(data.classAObj.count > 0)
{
Star s = new Star();
s.Area = "infinite";
s.Color = "red";
List<string> sep = data.Areas.Split(',').Select(string.Parse).ToList();
foreach(var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s.Values.Add(t);
}
p.Curves.Add(s);
}
return p ;
}
I would suggest inheriting the ClassA and ClassB from a common base as you did and then casting them, after typechecking. If your only goal is minimizing code-repition this will get your there:
class Program
{
static void Main(string[] args)
{
ComponentClass[] c = new List<ComponentClass>().ToArray();//Data from 3rd party;
foreach (var data in c)
{
Parent p = new Parent();
if (data.classObjs.Count > 0)
{
Star s = new Star
{
Area = "infinite",
Color = "red"
};
foreach (var b in data.classObjs)
{
string bStr = b.GetType() == typeof(ClassA) ? ((ClassA)b).City : ((ClassB)b).Village;
bStr = bStr.Split(',').Select(string.Parse).ToList();
TinyStar t = new TinyStar
{
smallD = bStr
};
s.Values.Add(t);
}
p.Curves.Add(s);
}
}
}
public class ComponentClass
{
public List<ClassObj> classObjs { get; set; }
}
public class ClassObj
{
public int ID { get; set; }
public string Countries { get; set; }
}
public class ClassA : ClassObj
{
public string City { get; set; }
}
public class ClassB : ClassObj
{
public string Village { get; set; }
}
}
It might be necessary to refactor the tenary to if...else or switch depending on if you add more classes of type ClassObj.
Be warned though that GetType actually queries the assembly (at runtime) and should be used with caution from a performance point of view as it can slow down applications a lot when executed often.
I have used reflection, check if it works for you
public static void CommonMethod(dynamic collection)
{
Parent p = new Parent();
Star s = new Star();
s.Area = "infinite";
s.Color = "red";
foreach (var data in collection)
{
var properties = data.GetType().GetProperties();
foreach (var p in properties)
{
string propertytName = p.Name;
var propertyValue = p.GetValue(data, null);
if (propertytName == "City" || propertytName == "Village")
{
List<string> sep = propertyValue.Split(',').ToList();
foreach (var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s.Values.Add(t);
}
p.Curves.Add(s);
}
}
}
}
static void Main(string[] args)
{
ComponentClass[] c Data from 3rd party;
foreach (var data in c)
{
CommonMethod(data.classAObj);
CommonMethod(data.classBObj);
}
}
I'm working on a project that consists of multiple objects that I want to save to my database. I'm using a single context and a series of repository classes to access them.
When I try to save an entity, it seems to save all the virtual entities associated with it, even if that entity exists in the database already.
These are my classes:
public class Requirement
{
public int ID { get; set; }
public DateTime DateDue { get; set; }
public DateTime DateCompleted { get; set; }
public virtual Standard Standard { get; set; }
public virtual Project Project { get; set; }
}
public class Standard
{
public int ID { get; set; }
public int AgencyID { get; set; }
public string Name { get; set; }
public virtual Agency Agency { get; set; }
}
public class Project
{
public int ID { get; set; }
public bool Active { get; set; }
public virtual Agency Agency { get; set; }
public virtual Department Department { get; set; }
}
And this is the method I have for creating some data:
public class RequirementRepository
{
public static string CreateMockData()
{
StandardRepository stdRep = new StandardRepository();
ProjectRepository projRep = new ProjectRepository();
RequirementRepository reqRep = new RequirementRepository();
Project project = projRep.Find(1);
StringBuilder sb = new StringBuilder()
foreach (Standard s in stdRep.FindByAgencyID(project.Agency.ID))
{
Requirement r = new Requirement();
r.Project = project;
r.Standard = s;
r.DateCompleted = (DateTime)SqlDateTime.MaxValue;
r.DateDue = DateTime.Now.AddDays(90);
r = reqRep.Save(r);
sb.AppendLine(String.Format("Saved Requirement ID {0} with Project ID {1}<br>", r.ID, r.Project.ID));
}
return sb.ToString();
}
}
And here is associated repository code:
public class ProjectRepository
{
public Project Find(int id)
{
using (var db = new MyContext())
{
return db.Projects
.Include(p => p.Agency)
.Include(p => p.Department)
.First(p => p.ID.Equals(id));
}
}
}
public class StandardRepository
{
public List<Standard> FindByAgencyID(int agencyID)
{
using (var db = new MyContext())
{
return db.Standards.Where(r => r.AgencyID == agencyID).ToList();
}
}
}
public class RequirementRepository
{
public Requirement Save(Requirement requirement)
{
using (var db = new MyContext())
{
Requirement retVal = requirement;
if (requirement.ID.Equals(0))
{
retVal = db.Requirements.Add(requirement);
}
else
{
db.Entry(requirement).State = EntityState.Modified;
}
db.SaveChanges();
return retVal;
}
}
}
When I run this method, I expect it to insert a number of new Requirements into the database with the project ID of 1 and a standard ID of whatever standard it's on. Instead, it creates a whole new project and a whole new standard for every requirement it adds, then assigns those IDs to the requirement.
Each context keeps track of the entities loaded, modified and the entities added.
Your repositories need to look something like this....
public class StandardRepository
{
MyContext _context;
public StandardRepository(MyContext context)
{
_context = context;
}
public List<Standard> FindByAgencyID(int agencyID)
{
return _context.Standards.Where(r => r.AgencyID == agencyID).ToList();
}
}
public class RequirementRepository
{
MyContext _context;
public RequirementRepository(MyContext context)
{
_context = context;
}
public Requirement Save(Requirement requirement)
{
Requirement retVal = requirement;
if (requirement.ID.Equals(0))
{
retVal = _context.Requirements.Add(requirement);
}
else
{
_context.Entry(requirement).State = EntityState.Modified;
}
_context.SaveChanges();
return retVal;
}
}
public class RequirementRepository
{
public static string CreateMockData()
{
using(MyContext context = new MyContext())
{
StandardRepository stdRep = new StandardRepository(context);
ProjectRepository projRep = new ProjectRepository(context);
RequirementRepository reqRep = new RequirementRepository(context);
Project project = projRep.Find(1);
StringBuilder sb = new StringBuilder()
foreach (Standard s in stdRep.FindByAgencyID(project.Agency.ID))
{
Requirement r = new Requirement();
r.Project = project;
r.Standard = s;
r.DateCompleted = (DateTime)SqlDateTime.MaxValue;
r.DateDue = DateTime.Now.AddDays(90);
r = reqRep.Save(r);
sb.AppendLine(String.Format("Saved Requirement ID {0} with Project ID {1}<br>", r.ID, r.Project.ID));
}
}
return sb.ToString();
}
}
From my understanding, you shouldn't have to manually set the state of the object you have modified unless you have detached it from its context. EF keeps track of the object state.
I like to use something like this:
public abstract class EntityRepositoryBase<TEntity> : IDisposable, IEntityRepositoryBase<TEntity> where TEntity : class , IEntityWithId
{
protected EntityRepositoryBase()
{
Context = new SomeEntities();
}
public abstract ObjectSet<TEntity> EntityCollection { get; }
public SomeEntities Context { get; set; }
public TEntity GetById(int id)
{
return EntityCollection
.FirstOrDefault(x => x.Id == id);
}
public void Dispose()
{
Context.Dispose();
}
}
Then in the deriving repositories:
public class AnswerRepository : EntityRepositoryBase<AnswerEntity>, IAnswerRepository
{
public override ObjectSet<AnswerEntity> EntityCollection
{
get { return Context.AnswerEntities; }
}
}
I inject the Repositories into the relevant class using ninject but you should be able to get similar with:
using (var repo = new AnswerRepository())
{
// modifying via Context
var someEntity = repo.GetById(someId);
someEntity.Value = "1";
repo.Context.SaveChanges();
//modifying via repo
repo.Delete(anotherEntity);
}
and then doing what you need to do. The context is exposed via the interface IEntityRepositoryBase should you need to perform out-of-repository modifications and then SaveChanges() as well as any specific CRUD type methods in your repo. Once out of scope the object and the underlying connection will be closed.
Is it possible to deserialize part of a binary file?
Basically I have an object similar to below, which I serialize into a binary file.
public class MyObject
{
public string Name { get; set; }
public int Value { get; set; }
public IList<MyOtherObject> { get; set; } // lots of data in here (order of kB-MB)
}
What I would like is to be able to deserialize only Name and Value by way of populating a ListView for file selection purposes and then deserialize the rest of the file when needed (i.e. the user chooses that file from the ListView).
As always, any help greatly appreciated and if any 3rd party libraries are suggested they would need to be able to be used freely in a commercial environment.
protobuf-net can do that, because it is not tied to the specific type; for example:
using ProtoBuf;
using System.Collections.Generic;
using System.IO;
[ProtoContract]
public class MyOtherObject { }
[ProtoContract]
public class MyObject
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public int Value { get; set; }
[ProtoMember(3)]
public IList<MyOtherObject> Items { get; set; }
}
[ProtoContract]
public class MyObjectLite
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public int Value { get; set; }
}
static class Program
{
static void Main()
{
var obj = new MyObject
{
Name = "abc",
Value = 123,
Items = new List<MyOtherObject>
{
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
}
};
using (var file = File.Create("foo.bin"))
{
Serializer.Serialize(file, obj);
}
MyObjectLite lite;
using (var file = File.OpenRead("foo.bin"))
{
lite= Serializer.Deserialize<MyObjectLite>(file);
}
}
}
But if you don't want two different types, and/or you don't want to have to add attributes - that can be done too:
using ProtoBuf.Meta;
using System.Collections.Generic;
using System.IO;
public class MyOtherObject { }
public class MyObject
{
public string Name { get; set; }
public int Value { get; set; }
public IList<MyOtherObject> Items { get; set; }
}
static class Program
{
static readonly RuntimeTypeModel fatModel, liteModel;
static Program()
{
// configure models
fatModel = TypeModel.Create();
fatModel.Add(typeof(MyOtherObject), false);
fatModel.Add(typeof(MyObject), false).Add("Name", "Value", "Items");
liteModel = TypeModel.Create();
liteModel.Add(typeof(MyOtherObject), false);
liteModel.Add(typeof(MyObject), false).Add("Name", "Value");
}
static void Main()
{
var obj = new MyObject
{
Name = "abc",
Value = 123,
Items = new List<MyOtherObject>
{
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
}
};
using (var file = File.Create("foo.bin"))
{
fatModel.Serialize(file, obj);
}
MyObject lite;
using (var file = File.OpenRead("foo.bin"))
{
lite = (MyObject)liteModel.Deserialize(
file, null, typeof(MyObject));
}
}
}
How about putting the Name and Valueinto a superclass and serializing them separately?
Alternatively, you could maintain a Dictionary and serialize that into one file.