I red this article: The entity cannot be constructed in a LINQ to Entities query , but guess it's not fully related to my issue.
I have this code:
public class Class1
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
[Table("Class2")]
public class Class2
{
[Key]
[Column("Prop1")]
public string Prop1 { get; set; }
[Column("Prop2")]
public string Prop2 { get; set; }
[Column("Prop3")]
public string Prop3 { get; set; }
}
and method edit where I want to use these ones:
using (var data = new Context())
{
var config = data.Class2.FirstOrDefault(c => c.Prop1.Contains(some_string));
if (config != null)
{
config.Prop1 = class1_instance.Prop1;
config.Prop2 = class1_instance.Prop2;
config.Prop3 = class1_instance.Prop3;
}
data.Entry(config).State = EntityState.Modified;
data.SaveChanges();
}
So what I want to get is simplify editing, instead of assigning each property one by one I want to write something like config = class1_instance;
So I've inherited Class1 from Class2, but getting
System.NotSupportedException (the entity or complex type "Class1" cannot be constructed in a Linq to Entities query).
How can I handle it?
Don't inherit the DTO class from the entity class because EF6 will treat the DTO as an entity participating in some of the supported database inheritance strategies.
Instead, use the SetValues(object) of the DbPropertyValues returned by the CurrentValues property of the DbEntityEntry:
Sets the values of this dictionary by reading values out of the given object. The given object can be of any type. Any property on the object with a name that matches a property name in the dictionary and can be read will be read. Other properties will be ignored. This allows, for example, copying of properties from simple Data Transfer Objects (DTOs).
e.g.
Class1 source = ...;
var target = data.Class2.FirstOrDefault(...);
if (target != null)
{
data.Entry(target).CurrentValues.SetValues(source);
data.SaveChanges();
}
Note that the target entity is already attached (tracked) by the db context, so there is no need to set the entry state to Modified.
Now Class1 and Class2 have equal properties. Is that intended, or is this by accident, and might it be that future versions of Class2 have properties that are not in Class1?
In entity framework, the DbSet<...> represent the tables of your database. the class in the DbSet represents one row in the table. The columns of your table are the non-virtual properties of the class; the virtual properties represent the relations between the tables (one-to-many, many-to-many, ...)
Class2 represents a database table. If Class1 is supposed to be equal to Class2, then what is the reason for Class1. If this equality is only now, and in future versions they might be different, you'll have to copy the properties one-by-one.
void UpdateValue(string someString, Class1 value)
{
using (var dbContext = new DbContext())
{
Class2 fetchedData = dbContext.Class2.Where(...).FirstOrDefault();
if (fetchedData != null)
{ // data exists. Update the properties
fetchedData.Prop1 = value.Prop1,
fetchedData.Prop2 = value.Prop2,
fetchedData.Prop3 = value.Prop3,
// future version of Class2 may have properties that are not updated
// no need to set state to modified. Entity Framework will detect the changes
dbContext.SaveChanges();
}
}
}
If you are absolutely certain that every Class2 is a special type of Class1, now and in far future, you might consider to derive Class2 from Class1:
class Class2 : Class1
{
public int Id {get; set;}
... // properties that are in Class2, but not in Class1
}
This means that every non-virtual property of Class1 is represented by a column in the tables with Classes2.
Derivation won't help you, even if you derive, you'll have to copy the properties one by one. If you'll have to do this several times consider to create a function that copies the proper values for you.
Related
I was wondering if I have an object that contains a field which has its deserialization process dependant on another field, how can I deserialize the parent object?
Container
class Container
{
public int Id { get; set; }
public object Data { get; set; } //deserialization depends on first field
}
Hierarchy
class FieldType1
{
public string Value { get; set; }
}
class FieldType2
{
public int Numbers { get; set; }
}
Given the example above if I have a Dictionary<int,Type> how can I deserialize an object that comes as a string like the one below?:
var container = new Container { Data = new FieldType1 { Value = "sata" }};
var str = JsonConvert.SerializeObject(container);
var clone = JsonConvert.DeserializeObject<Container>(str);//has dependant field on another field
As you can see in my example above I always have the same container type.but one property differs.
Update
After some answers here could it be possible to keep only one type of parent object and instead have a base type for the second field ?
[JsonSubTypes.KnownSubType(typeof(Child1),1)]
[JsonSubTypes.KnownSubType(typeof(Child2),2)]
public abstract Child
{
}
public class Parent{
public int Id;
public Child child;
}
Can i decorate somehow the parent to know how to deserialize its second field (similar to JsonSubTypes)?
Summing it up i do not want to have P,P1,P2..Pn types for parent.
I want to have one type P for parent with F1,F2...Fn types for its second field.So that when i deserialize i would just say JsonConvert.DeserializeObject<P> while the converter takes care of which concrete type is the second field:
Parent c1=new P{ id=1,child=new Child1()};
Parent c2=new P{ id=2,child=newChild2()};
List<Parent> items=new List<Parent>{c1,c2};
var str=JsonConvert.SerializeObject(items);
var clone=JsonConvert.DeserializeObject<List<Parent>>(str);
At a first glance, I'd simply use a simple function that you could put into a SomeNameParser/Converter class.
Pesudo C# code, something like the following:
var jObject = JObject.Parse(obj.Data);
switch (jObject["firstField"])
{
case "fieldType1":
return JsonConvert.DeserializeObject<string>(str);
case "fieldType2":
return JsonConvert.DeserializeObject<int>(str);
default:
Throw new Exception( make this meaningful)
}
Improvements
You could make the parsing of the firstField do a lookup to return a System.Type, then pass the type to JsonConvert.Deserialize(obj.Data, type) which would save the repetitive JsonConvert.
Hopefully you can see the general pattern.
I have been tasked with writing a routine against an existing database. This database has several tables that have identical structures, but different names (I did not design this, please do not suggest database design change). I am writing this in EF, and the models were created database-first.
The best option I can think of for this situation is to create a class that has the exact same properties, and create a routine that can accept generic types to copy data from the EF model to the generic model.
My models:
// Sample EF database-first created model
namespace SampleDataModel.Models
{
using System;
using System.Collections.Generic;
public partial class SampleClassFlavorOne
{
public int Id {get; set;}
public string PropertyOne {get; set;}
public string Property2 {get; set;}
public DateTime Property3 {get; set;}
}
}
// Sample of generic class I created
public class GenericSampleClass{
public int Id {get; set;}
public string PropertyOne {get; set;}
public string Property2 {get; set;}
public DateTime Property3 {get; set;}
}
My routine:
private static void CopyFlavorToGenericList<T1, T2>(List<T1> fromList, List<T2> toList){
foreach (var t in fromList)
{
//(As you can see, I have tried entering the foreach loop a both ways
//foreach (var p in typeof(T1).GetProperties())
foreach (var p in typeof(T2).GetProperties())
{
if (p != null && p.CanWrite)
{
dynamic newObject = null;
p.SetValue((T2)newObject, p.GetValue(t, null), null);
}
}
toList.Add(toObject);
}
}
Implementing the routine:
switch (flavor){
case "FlavorOne":
List<SampleClassFlavorOne> _baseFlavor = db.SampleClassFlavorOne.ToList();
List<GenericSampleClass> _genericFlavor = new List<GenericSampleClass>();
CopyFlavorToGenericList<SampleClassFlavorOne, GenericSampleClass>(_baseFlavor, _genericFlavor);
break;
}
No matter what I try, I always get:
An exception of type 'System.Reflection.TargetException' occurred in mscorlib.dll but was not handled in user code. Additional information: Object does not match target type.
I cannot figure out what I am missing.
What may I be missing?
Am I going about this the wrong way? If so, what is the correct way to do what I want to do given these conditions?
Any help appreciated, thanks!
Your call to GetProperties() gets an array of PropertyInfo objects that apply to that specific type. Thus, when you call GetValue(), you are trying to get the value from an object of the wrong type.
I.e. T2, the type used to get the PropertyInfo object, is GenericSampleClass, but the type of the object you pass to the GetValue() method is SampleClassFlavorOne. In your alternative, getting the properties from T1, you have the same problem, but with the SetValue() method, passing (in theory…but not really, see "Note:" below) an object of type GenericSampleClass, when the PropertyInfo object came from the SampleClassFlavorOne type.
To do this correctly, you need to get the PropertyInfo objects from both classes, and use them with the objects of the appropriate type. For example:
private static void CopyFlavorToGenericList<T1, T2>(List<T1> fromList, List<T2> toList) where T2 : new()
{
var map = from p1 in typeof(T1).GetProperties()
join p2 in typeof(T2).GetProperties()
on p1.Name equals p2.Name
select new { From = p1, To = p2 };
foreach (var t in fromList)
{
T2 toObject = new T2();
foreach (var copyItem in map)
{
if (copyItem.To.CanWrite)
{
copyItem.To.SetValue(toObject, copyItem.From.GetValue(t));
}
}
toList.Add(toObject);
}
}
Note: you also had an issue with how you were creating the new object. I don't even know what you meant, using dynamic like that, but it wouldn't have worked. You were just passing null as the value of the destination object, which doesn't do anything useful.
You need to be able to create instances of the destination object as needed, and the way to do that in the generic method is to add the new() constraint to the generic type parameter to require the destination type has a parameterless construction, so that you can in fact use the expression new T2() to create a new instance of the object.
I am working on a ASP.NET MVC project, with C#, and EF code first.
I am required to add dynamic properties to entities. For example -
I have a car as a base object. I can add custom properties for it like engine power, length, color etc etc.
Properties can be boolean, int, string or select options (ie, i have to create checkbox, input or select html elements when a user inputs values for those properties).
Properties must have custom validation rules (i.e., required, number only, range only etc).
Can you guys give me any clues or direction how to accomplish this?
Thank you
If you truly have dynamic properties you won't be able to do this (directly) with EF6 since EF6 assumes a relation database. and a relational database needs to know which columns to expect.
Now you got 2 options.
Option1:
use a non-relational database with EF 7. you can look here https://msdn.microsoft.com/en-us/magazine/dn890367.aspx for some more details about EF7 but basically in a non relation database you can store any json blob - so also your dynamic properties
Option 2: Use a key value pair within your object. and store those properties
class KeyValuePair {
int Id {get; set;}
string name {get; set;}
string stringValue {get; set;}
}
class BaseObject {
int Id {get; set;}
list<KeyValuePair> dynamicProperties {get; set;}
}
Now your car can just inherit from this baseobject. You still need to do the work to create your KeyValuePair objects. (And if you want to store strings, ints etc you can make Different KeyValuePair types, one for each storage type)
Be carefull with performance though if you use dynamic properties like this.
Update:
If you want to validate a dynamic object like this you want to implement IValidatableObject
so you get
class Car: BaseObject, IValidatableObject {
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
/* code to validate your properties here, for example you need at least 1 engine, 4 wheels etc */
yield return ValidationResult.Success;
}
}
You can create and use tables in DB dynamically, although it's not so simply.
First, you'll need to store metadata about your tables — what are their names, what are properties they have, what are the types of those properties, and so on.
Second, you'll need to generate entities to access these tables, and also, EntityTypeConfiguration classes, like here:
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FooTypeConfiguration : EntityTypeConfiguration<Foo>
{
public FooTypeConfiguration()
{
ToTable("Foos");
HasKey(t => t.Id);
Property(t => t.Name).HasMaxLength(200)
.IsRequired();
}
}
You can generate DLL dynamically without intermediate C# code with help of System.Reflection.Emit. Or you can generate C# code and use System.CodeDom.Compiler to compile it (this way is simpler). You can also try Roslyn compiler (but I don't have enough experience to advise it).
Third, you'll need to load compiled DLL and create DbContext using modelBuilder.Configurations.AddFromAssembly(...).
You can find required type in assembly and use it to access data:
string typeName = ...;
var type = dynamicLoadedAssembly.GetType(typeName);
var set = dbContext.Set(type); // non-generic DB Set
You can use System.Reflection or dynamic typing to work with these objects.
Finally, if you'll generate C# code, you can generate properties and implementation of some interface to access these properties by names:
public interface IAccessorByName : IReadOnlyDictionary<string, object>
{
object this[string name] { get; set; }
}
public Foo : IAccessorByName
{
private static readonly IDictionary<string, Func<Foo, object>> getters = new Dictionary<string, Func<Foo, object>>
{
{ "Id", (foo) => foo.Id },
{ "Name", (foo) => foo.Name },
};
private static readonly IDictionary<string, Action<Foo, object>> setters = new Dictionary<string, Action<Foo, object>>
{
{ "Id", (foo, value) => { foo.Id = (int)value; } },
{ "Name", (foo, value) => { foo.Name = (string)value; } },
};
public int Id { get; set; }
public string Name { get; set; }
public object this[string name]
{
get { return getters[name](this); }
set { setters[name](this, value); }
}
}
With similar interface you can create, read, update, and delete objects dynamically:
string typeName = "Foo";
var fooType = dynamicLoadedAssembly.GetType(typeName);
var foo = (IAccessorByName)Activator.CreateInstance(fooType);
foo["Id"] = 1;
foo["Name"] = "Jon Skeet";
var fooSet = dbContext.Set(fooType);
fooSet.Add(foo);
dbContext.SaveChanges();
I have two lists of different objects, one from a third party API and one from my database - and I'm trying to link the two as a relationship. Ideally with a similar effect of how DBML's create relationships for tables with foreign keys (Customer.Orders).
From third party:
class ApiObject {
public string ID { get; set; }
public string Title { get; set; }
public DateTime CreatedDate { get; set; }
... 30 other properties ...
}
From my database:
class DbmlObject {
public int ID { get; set; }
public string ApiID { get; set; }
public string OtherString { get; set; }
}
They are related through ApiObject.ID == DbmlObject.ApiID
I do not want to merge these, nor join them into some anonymous object (and explicitly list 30+ properties) - but rather to make the DbmlObject a linked property of ApiObject. i.e.: addressable as:
apiObject.DbmlObjects.First().OtherString or ideally apiObject.DbmlObject.OtherString since it is a 1 to 1 relationship.
In controller:
List<ApiObject> apiObjects = _thirdParty.GetObjects();
DbmlDataContext model = new DbmlDataContext();
List<DbmlObject> dbmlObjects = model.GetAllDbmlObjects();
// relate them here
foreach (var apiObject in apiObjects)
Console.Write(apiObject.DbmlObject.OtherString)
// NOTE: ideally this foreach loop should not make a DBML query on each iteration, just the single GetAllDbmlObjects query above.
It sounds like a join:
var combined = from api in apiObjects
join dbml in dbmlObjects on api.ID equals dbml.ApiID
select new { api, dbml }
In order to get DbmlObject "in" the ApiObject, you will need to either inherit ApiObject and construct a new one of that class, which includes the Dbml property, or create a entirely new class to return. If you need static typing this is the best you can do - of course you could (mis)use dynamic to get what you want.
In this case, you are mentioning (in comments) that the ApiObject class is from a third party library that you can't change - in this case I would probably choose to create a new type which takes an instance of both objects in the constructor and exposes the properties you need - a decorator. Yes, it looks like a lot of code, but it is not complex, good tools will autogenerate it for you - and you get the class that you need for your code to be succinct.
In case you want to go further with returning an IEnumerable<dynamic>, you could build a "combining dynamic" object based on DynamicObject that then responds to all the properties of ApiObject and DbmlObject - or just adds DbmlObject as a property. I am not saying this is the right way to go, it depends on what you need it for - remember you are losing type safety. Here is a simple example:
void Main()
{
dynamic dyn = new CombiningDynamic(new Foo { X = 3 }, new Bar { Y = 42 });
Console.WriteLine(dyn.X);
Console.WriteLine(dyn.Y);
}
public class Foo
{
public int X {get;set;}
}
public class Bar
{
public int Y { get;set;}
}
public class CombiningDynamic : DynamicObject
{
private object [] innerObjects;
public CombiningDynamic(params object [] innerObjects)
{
this.innerObjects = innerObjects;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
foreach(var instance in innerObjects)
{
Type t = instance.GetType();
PropertyInfo prop = t.GetProperty(binder.Name);
if (prop != null && prop.CanRead)
{
result = prop.GetValue(instance, null);
return true;
}
}
result = null;
return false;
}
}
Remember, this is example code. If you really go this way, you would want to perhaps override some more of the methods (TrySetMember, ...), and you most definetely would want to cache the reflection results so you don't need to walk the types each time - reflection is (comparatively) slow.
Due to a recent issue i had some days ago (you can check this post here), i needed to create a way that some of my linq to sql tables could be referenced dynamically. I've managed to do that through an abstract LogTable class, which contains all my LogTable properties as defined on my DataTable. I was able to do this abstract way because my LogTables have the same structure, thus the same properties.
Heres the reducted code:
Abstract base class
public abstract class LogTableStructure
{
public int ID { get; set; }
public datetime? LastAccess { get; set; }
public string Username { get; set; }
}
My (reducted) dynamic method to update a LogTable:
public void UpdateLog<T>(T currentLOG) where T : LogTableStructure
{
LogTableStructure logStructure = null;
//LogTableEnum is defined on this class constructor
switch (LogTableEnum)
{
case LogTableEnum.Log2009:
logStructure = this.factory.LogDB.LOG_2009s
.SingleOrDefault(q => q.ID == currentLOG.ID);
break;
case LogTableEnum.Log2010:
logStructure = this.factory.LogDB.LOG_2010s
.SingleOrDefault(q => q.ID == currentLOG.ID);
break;
case LogTableEnum.Log2011:
logStructure = this.factory.LogDB.LOG_2011s
.SingleOrDefault(q => q.ID == currentLOG.ID);
break;
}
}
PROBLEM
for some reason the currentLOG param throws a runtime null reference exception, even though it has all LogTable properties filled. I've notice by using vs2010 debbuger that while the currentLOG properties are filled, the base class (LogTableStructure) properties are all empty, as if the base object is null.
Am i forgeting something about member hide inheritance or something alike? I've even added the new modifier to all my LogTable properties on my .dbml, but even that didn't solve the problem
Just make the object into which you're injecting an actual instance:
// This object is going to have to be a class that inherits from your abstract class
// It can't be a null object of the type of your abstract class.
var logStructure = new InstanceOfLogTableStructure();
logStructure.InjectFrom(currentLOG);
That should do it.
You seem to have your ordering wrong. You're assigning null to logStructure, then you're calling InjectFrom on it. Only then are you assigning a factory-created instance to that variable.