We are looking at adding an Exception property to one of our models that is currently mapped using Entity Framework code first.
Is there a way to map a property of type Exception directly somehow, perhaps by making it binary serialized in the database, thus maintaining a type-safe model class?
I assume I could make this work somehow by implementing two properties in the model, for instance:
public Exception Exception {get; set;}
internal byte[] SerializedException {get; set;}
Then, I would mark the real exception property as Ignore on the modelbuilder inside the context and let EF use the binary version. This is obviously very clumsy, as I would need to implement the serialization/deserialization in the getter/setter for the real exception and, as I said, I'm only assuming it's possible, but have not yet tested it.
I'm very curious if it is somehow possible to implement this using the type directly.
Unfortunately, I don't believe there is any way to do what you want with EF. The normal solution is to use the internal property like you mentioned above - just have Exception deserialize from the backing property the first time it is accessed.
It's not pretty, but EF does not expose an extension point for plugging in custom type converters between the POCO and the database, so it's the best we can do.
Related
Pardon my question if this has been asked before but I'm not 100% sure if my google wording is not accurate or if this just isn't a normal thing.
I have a WCF service where I need to pass in any type of Entity Framework model object (unknown by virtue of the fact that I need to treat these objects nearly identically without writing a new interface contract for each model because they all save the same way, for example).
So far, this is great. They're passed in, I seem to be getting the type just fine (I think so far) so I can treat them "generically."
My new conundrum is: How do I get the reference to the database connection string from the entity object?
Is there a way to say something similar to (pardon some of the extreme psuedo here):
object DbContext = genericEFObject.databaseEntityConnection; //need help here
typeof(DBContext) db = typeof(DBContext); //possibly help here too
db.Entry(genericEFObject).State = System.Data.Entity.EntityState.Added;
db.SaveChanges();
I'd like to avoid passing in the db object to the contract, if possible.
Any awesomeness to be had here?
I'm sorry to say that there's not any remotely easy way to do this. You'll have to write a lot of code and abuse Reflection like it's going out of style. These are your options as far as I can see:
Generic method
The DbContext is not getting serialized and passed over WCF. So that will leave you with either a POCO Entity object to create, update or delete or a nice long expression tree representing a query. You then have to figure out what DbContext it belongs to, instantiate said DbContext, figure out what DbSet it belongs to, and use it on the DbSet all via reflection.
Code generation
You will still need a lot of reflection to pull out all the DbContexts and DbSets but once you have those, generating methods for all of them should be a breeze. You'll have a lot more flexibility as to what conventions you can apply to different operations. The downside is that there will be a lot of code there and it might get a little hard to manage unless you find some way to break it up into different namespaces.
Normally, the answer is NO - it is not possible to get context instance from an entity object without doing some reflection things. This is generally considered a bad practice to have entities that are aware of the storage they were produced from.
However, because of the way Entity Framework is implemented right now (v6.1.1), technically there is a way to achieve this in a 'hacking manner' when your context configured to create proxies (ProxyCreationEnabled = true).
Here's a very bad code that will give you an ObjectContext from an entity object (warning: do not even consider to use this in production):
var ctx = new MyContext();
ctx.Configuration.ProxyCreationEnabled = true;
dynamic dynamicEntity = ctx.Employees.First();
var entityWrapper = dynamicEntity._entityWrapper;
Type type = entityWrapper.GetType();
var contextProperty = type.GetProperty("Context");
var objectContext = contextProperty.GetValue(entityWrapper) as ObjectContext;
This is my first activity with great stack overflow, but absolutely not my first time to visit the website.
My Question:
In our project, we are extending the EntityTypeConfiguration to take control over the mapping of entities to the DB in code first fluent API.
What I am confused with is how it is possible to include the configuration of complex types in the ctor of derived configuration, i.e. The configuration of primitive properties is possible through "Property" method of base EntityTypeConfiguration, but when calling this method on properties of type of Complex Types, the project builds will stop at called method.
Actually, the DB will be generated by entity table containing multiple columns, representing the fields of the embedded Complex Type using "PROPERTYNAME_INNERFIELDNAME" naming convention, even though if the complex type be of class type.
So, I do not know how to overcome with the issue if the complex type be of class type.
Thank you for your kind consideration.
My Code:
class Entity
{
long Id;
Address Addr;
}
class Address
{
string City;
string ZipCode;
}
class EntityConfig : EntityTypeConfiguration<Entity>
{
EntityConfig()
{
Property(p=>p.Addr); //Build error
}
}
Firstly, thanks to dear Bardware.
My problem has been solved by using following configuration:
Property(p=>p.Addr.City);
Property(p=>p.Addr.ZipCode);
Actually, I could not use "ComplexTypeConfiguration" instead of EntityTypeConfiguration because I would loose my chance to use HasKey, HasRequired etc.
I'm getting the following error when trying to run a solution using Entity Framework 4.0 and am wondering how to change the mapping settings to correct it:
Problem in mapping fragments starting at line 588: Must specify mapping for all key properties (UserDatas.Id) of the EntitySet UserDatas
To give some background - I originally created the tables shown below with Modified/Created Date/By and Id columns in each of them, but then decided to pull them out into the abstract UserData and then use inheritance instead. Since I changed this it's all gone to pot!
Does anyone have any pointers as to where I'm going wrong? I've been using the design view show below (the GUI) and it feels like I've hit a brick wall.
My db.edmx design view looks like this, and clicking on the error takes me to the Variables table shown below, but the error is repeated for all the other tables that inherit this Id (please ignore all the links to other tables - I didn't want to post the whole big db schematic):
Many thanks.
Sounds like you are mis-using OO inheritance here. Just because objects share items with the same property names doesn't mean that they Inherit from the base. For example, ask yourself in your modle if Tag IS A UserData? I suspect you could phrase this better that Tag HAS A UserData which points to containment rather than inheritance. I would recommend setting up a common IUserData interface where each object implements the interface distinctly. In that case, your mapping then would move the properties for the UserData interface back into the underlying classes (as they were configured originally). While you may be able to get your mapping to work with the inheritance model, your queries will get significantly complex both from a LINQ and TSQL perspective.
I'm trying to write an add-on to Entity Framework Code First and I need a way to get the configuration of the model columns at run time. For example, this is the code setup on OnModelCreating by the DbModelBuilder:
builder.Entity<NwdEmployee>()
.Property(n => n.ReportsToID).HasColumnName("ReportsTo");
Once this is done, EntityFramework knows that my property's name is different to the column name in the table, but how can I find that the string "ReportsTo" relates to ReportsToID myself at runtime? Ideally, I'm trying to write a method such as a following:
public string GetMappedColumnName<TFrom>(DbContext context,
Func<TFrom, object> selector);
Which would be used like:
string mappedColumnName = GetMappedColumnName<NwdEmployee>(context,
x => x.ReportsToID);
I just don't know where to find the mapped column names within the DbContext. Are they even accessible?
Theoretically yes. Practically I'm not sure because with simple test I wasn't able to get those information at runtime - I see them in debugger but I cannot get them because the type I need to use is internal in entity framework.
The theory. All mapping information are available at runtime but not through reflection. They are stored in the instance on MetadataWorkspace class which was definitely not designed for direct usage because every interaction with this class demands some time spend in debugger before you find how to get data you need. This data are not accessible through DbContext API. You must convert DbContext back to ObjectContext and access the MetadataWorkspace.
ObjectContext objContext = ((IObjectContextAdapter)dbContext).ObjectContext;
GlobalItem storageMapping = objContext.MetadataWorkspace.GetItem<GlobalItem>("NameOfYourContextClass", DataSpace.CSSpace);
Now storageMapping is instance of System.Data.Mapping.StorageEntityContainerMapping class which is internal. As I understand it this class should be runtime representation of MSL = mapping between storage and conceptual model.
If you use debugger you can explore the instance and you will find information about mapping between properties and columns (its quite deep nested) so you can also use reflection to get them but it is reflection on non public interface of classes you don't own so any .NET framework patch / fix / update can break your application.
I have a Reason object:
public class Reason
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Company Company {get;set;}
}
I am using entity framework 4 and Company is navigation property to Company.
I also use webservices in order to return data to the client.
I have web method that returns Reasons:
[WebMethod]
public Reason[] GetCallReasons()
{
IReasonRepository rep =
ObjectFactory.GetInstance<IReasonRepository>();
return rep.GetReasonsList().ToArray();
}
Because of the ef4 I get the following exception for executing the web method:
A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Reason_24A0E4BBE02EE6BC2CF30BB56CFCB670C7D9D96D03D40AF4D174B89C9D3C5537'
The problem accurs because ef4 adds property that can't be serialized:
In order to solve this and eliminate the error, I can disable the navigation property by not making it virtual or by remove the navigation property. But I neet it and want to use the lazy loading feature.
I also can write spesific serializer for Reason but I have many many classes the I used in my web-services and write a serializer for all of them is a lot of work.
How can I solve this exception?..
There are multiple solutions for your problem and they really depend on the type of service you are using and on the type of serialization:
The clean approach is using DTO (data transfer objects) as #Mikael already suggested. DTO is special object which transfers exactly what you need and nothing more. You can simply create DTOs to not contain circular references and use AutoMapper to map between entities and DTOs and vice versa. +1 for #Mikael because he was the first to mentioned this.
All other approaches are based on tweeking serialization as #Haz suggested:
WCF and DataContractSerializer: explicitly mark your entities with DataContract[IsReference=true] and all properties with [DataMember] attributes. This will allow you to use circular references. If you are using T4 template to generate entities you must modify it to add these attributes for you.
WCF and DataContractSerializer: implicit serialization. Mark one of related navigation properties with [IgnoreDataMember] attribute so that property is not serialized.
XmlSerializer: mark one fo related navigation properties with [XmlIgnore] attribute
Other serializations: mark one of related navigation properties with [NonSerialized] (+1 for Haz he was the first to mention this) for common serialization or [ScriptIgnore] for some JSON related serialization.
I usually write specific classes for the webservice. While this is some extra work it has the advantage that the webservice gets more robust as small changes in your entities won't go unoticed and silently fail on the side of the consumer/javascript. For example if I change the name of a property.
There are a few things you can do to reduce the work and one is to use AutoMapper which can automatically map between objects.
You haven't supplied the definition for your company class.... But I'm guessing you have a collection of Reason as a property.
Lazy loading in an SOA Enviroment doesn't really work. You can't have unlimited lazy navigation over a serialized class, once you leave the webmethod you have no way to call back into the original datacontext from the webmethod consumer to lookup the properites... so the serializer will try and visit all properties, including lazy properties at the time of serialization.
You need to disable serialization on one part of the circular reference, either on the Reason collection in Company class, or the Company in Reason class.
You can use the "NotSerialized" attribute to disable serialization of a particular field.