Entity Framework 6 doesn't detect inheritance - c#

I have the following class setup
public abstract class SearchElement
{
public int Id { get; set; }
public SearchElement parent { get; set; }
public int Order { get; set; }
public UserQuery UserQuery { get; set; }
}
public class SearchGroup : SearchElement
{
public virtual ICollection<SearchElement> SearchObjects { get; set; }
public bool IsAndOperator { get; set; }
public SearchGroup()
{
this.SearchObjects = new List<SearchElement>();
}
}
public abstract class SearchCondition<IContext, OutputType> : SearchElement
{
public ComparisonTypes Comparison { get; set; }
public string Value { get; set; }
public abstract Expression<Func<OutputType, bool>> BuildConditionQuery(IContext context);
}
public class SearchPackage : SearchCondition<ISearchContext, ProjectParticipantQuestionnaireResponseGroup>
{
public override System.Linq.Expressions.Expression<Func<ProjectParticipantQuestionnaireResponseGroup, bool>> BuildConditionQuery(ISearchContext context)
{
return this.BuildCondition<ProjectParticipantQuestionnaireResponseGroup, int>(r => r.Package.Id, int.Parse(this.Value), this.Comparison);
}
}
Now for some reason, when in the EntityFramework context I specify:
public DbSet<SearchElement> SearchElements { get; set; }
The SearchGroup class gets detected and the appropriate fields get created in the SearchElement table. However, the SearchPackage class does not get detected and it's fields are not created in the SearchElement table.
I can of course create a DbSet for the SearchPackage, but there are multiple similar classes (same inheritance, although some with difference values) and I don't want to create a DbSet for each of them. Does anyone has suggestions about what I can do?
For clarity: I am using Entity Framework 6.1.3 and C# 4.5.1

EF 6 cannot map a CLR generic type. (Sorry, I can't find an authoritative reference on this right now.) This is the problem, not one of inheritance generally. When EF traverses your inheritance "tree," it gets to SearchCondition<,> and gives up.
Finding a way around this will probably require a rethinking of your object model to something more serialization-friendly. Is there a way that you can split your object-model into a set of services (that might contain generics) that interacts with a set of more easily mapped DTOs?
Another (possible, untested) option: Make an ISearchElement mapped interface. SearchPackage should implement it directly. This way, SearchPackage--and other SearchCondition<,> implementors should get "picked up" by EF inheritance traversal.

Related

Automapper Mapp from Interface to Interface

public I´ve got a Concrete Mapping from BusinessObject to DatabaseObject but within the Dbo there are some References which are also Dbo´s but with there Interfaces. So when I add a mapping as cfg.CreateMap<IBo, Dbo>(); The sub-reference cannot be resolved because there is no mapping from IDbo to Dbo I think:
Example:
public class BO1 : IBO1
{
public string Test { get; set; }
public IBO2 BO2 { get; set; }
}
public interface IBO1
{
string Test { get; set;}
IBO2 BO2 { get; set; }
}
public interface IBO2
{
int Some { get; set; }
}
public class DBO1 : IDBO1
{
public string Test { get; set;}
public IDBO2 BO2 { get; set; }
}
public interface IDBO1
{
string Test { get; set;}
IDBO2 BO2 { get; set; }
}
public interface IDBO2
{
int Some { get; set; }
}
Now I´ve got the following mapping:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<IBO1, DB1>();
cfg.CreateMap<IBO2, DB2>();
});
But this throws an not mapped exception. So how can I mapp nested interfaces?
EDIT:
The exception I get is as followed:
Missing type map configuration or unsupported mapping.
Mapping types:
ObjectProxy -> IDBO2
Castle.Proxies.ObjectProxy -> Models.IDBO1
Destination Member:
BO2
The simple answer, don't use interface references here, use the concrete classes. The issue will be that when creating a DB01, this tells Automapper that it wants an IDB02 for the BO2 and you've only told Automapper how to convert an IB02 into a DB02. not an ((IBO2)B02) into an ((IB02)DB02)
You can use a shared interface between your Entity and DTO/ViewModel if you want to use that as a contract to ensure that they are kept identical (or at least conforming to the same subset of members) but inside the ViewModels, the relationship references should be ViewModels, and within the Entities the relationships should be Entities. This risks breaking Interface Segregation as it's likely that DTOs and entities are not purely interchangeable and pretty soon there would be properties or methods added to the interface that apply to one and not the other. Plus it would be dangerous to have something like a DB01 reference a B02 or B01 reference a DB02. These entities should not be interchangeable so their references should be concrete.

Auto-generated class from EF6 to implement custom interface

I am using EF 6. I have a table in db for which the auto-generated class looks like this:
public partial class tblPreparation
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public tblPreparation()
{
this.tblPreparationItem = new HashSet<tblPreparationItem>();
}
public int id { get; set; }
public string name { get; set; }
public System.DateTime date { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<tblPreparationItem> tblPreparationItem { get; set; }
}
In my code, I want this class to extend another class EntityObject, which is in the namespace System.Data.Entity.Core.Objects.DataClasses (and implement another interface). So I created wrote this partial class:
public partial class tblPreparation : EntityObject, IMyInterface
{
}
It doesn't throw a syntax error but when I run the application I get runtime error: "The type 'tblPreparation' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive or generic, and does not inherit from EntityObject." What am I missing?
I assum it's because they are not in the same namespace. Is there a way to fix this?
I may have misunderstood your comment on the namespace, but for clarity, a Partial class is only actually a partial class when it is in the same namespace of the corresponding partial class, otherwise what you have are just two separate single classes with the same name claiming to be partial. If this is the case, the fix is simple. Put them in same namespace.
However, it is more likely due to adding the EntityObject to the class hierarchy, as oerkelens mentioned. EF 6 creates proxies of your POCOs, for this reason your classes must have parameterless constructors. Adding another class may prevent the db context from creating proxies of your objects.
Remove just that class from the hierarchy, check whether you can materialise these entities to verify or rule it out.
Edit - No, it definitely is due to EntityObject.
I reproduced this by first having my entity implement some interface in a partial class. That worked great. Then I had partial class inherit from EntityObject that failed with your error.
After reproducing this error, I created a class called MyStupidClass and replaced EntityObject with MyStupidClass and I could still materialise entities (even with the top level properties of EntityObject).
So it depends on the class you introduced to the hierarchy.
class Program
{
static void Main(string[] args)
{
using (var db = new schedulerEntities())
{
var schedules = db.Schedules.ToArray();
foreach (var schedule in schedules)
{
Console.WriteLine($"{schedule.Cron} - {schedule.FriendlyDescription}");
}
}
Console.ReadLine();
}
}
public partial class Schedule: MyStupidClass, IScheduler
{
public string FirstName { get; set; }
}
public class MyStupidClass
{
public EntityKey EntityKey { get; set; }
public EntityState State { get; set; }
}
interface IScheduler
{
long Id { get; set; }
string Name { get; set; }
string Cron { get; set; }
}

How to work with field of inherited classes in Entity Framework

Suppose, i have main class for data representation and this class have configuration field. This field must be able to answer some questions related to main class (assume, that this is one question - 'IsMainClassReadyToUse'). But inner structure of this class may be different.
Because of it, i want create abstract class Configurator and depending on situation use various Configuratos that implement its functional.
So, i have following code:
public class SimpleConfigurator : Configurator
{
public int FieldA { get; set; }
public override bool IsDataClassReadyToUse()
{
return ParentDataClass.FieldA == FieldA;
}
}
public class ComplexConfigurator : Configurator
{
public virtual List<int> FieldsB { get; set; }
public override bool IsDataClassReadyToUse()
{
return ParentDataClass.FieldsB.All(x => FieldsB.Any(y => y == x));
}
}
public abstract class Configurator
{
public int ConfiguratorId { get; set; }
public virtual DataClass ParentDataClass { get; set; }
public abstract bool IsDataClassReadyToUse();
}
public class DataClass
{
public int DataClassId { get; set; }
public virtual Configurator Configurator { get; set; }
public int FieldA { get; set; }
public virtual List<int> FieldsB { get; set; }
}
public class DataDbContext : DbContext
{
public DbSet<DataClass> DataClasses { get; set; }
}
But the problem appears when i try use DataClass instance with Configurator of type ComplexConfigurator.
Because of LazyLoading i need to load FieldsB from ComplexConfigurator, but abstract class Configurator doesn't contain such field and i can't write such code:
new DataDbContext().DataClasses
.Include(m => m.Configurator)
.Include(m => m.Configurator.FieldsB);
I tried to disable LazyLoading, adding such constructor in DataDbContext:
public DataDbContext()
{
Configuration.LazyLoadingEnabled = false;
}
But when i try get access to FieldsB it still be null.
So, how can i implement such architecture with Entity Framework?
Or maybe i should choose another architecture for such task?
I think you should try access you configurator such as
((ComplexConfigurator)yourObject.Configurator).FieldsB
But I'm afraid EF works wrong with List<int> property (when I tried do that sometimes I've got a fail) and better way is to create class Option and field List<Option> Options into your configurator instead of List with integers.
You also should check your DB scheme (there's should be a table "Configurators" with idenitifator field and all SimpleConfigurator and ComplexConfigurator's fields). May be you should add DbSet<Configurator> into your DbContext definition.
You can read this article for getting more information about inheritance and EF.

Best method to inherit common properties/methods into several models in Asp.NET MVC

Many tables in my database have common fields which I call 'audit' fields. They fields like - UserUpdateId, UserCreateId, DateUpdated, DateCreated, DateDeleted, RowGUID, as well as a common "Comments" table etc. In the database they are used to track who did what when. Additionally via the asp.net MVC 4 views they display these attributes to the user using common display templates (popup, mouseover etc.).
Currently, I put these properties into a [Serializable()] CommonAttributesBase class. Which I then initialize in all the models that should inherit those properties. Admittedly this is a little clunky and inefficient as my CommonAttribute class makes calls to the repository and the initialization seems like more code than necessary.
I would appreciate suggestions on how to implement this in the best way.
[Serializable()]
public class CommonAttributesBase
{
#region Notes
public Boolean AllowNotes { get; set; }
[UIHint("NoteIcon")]
public NoteCollection NoteCollection
{
get
{
if (!AllowNotes) return null;
INoteRepository noteRepository = new NoteRepository();
var notes = noteRepository.FindAssociatedNotes(RowGUID);
return new NoteCollection { ParentGuid = RowGUID, Notes = notes, AuditString = AuditTrail };
}
}
#region Audit Trail related
public void SetAuditProperties(Guid rowGuid, Guid insertUserGuid, Guid updateUserGuid, Guid? deleteUserGuid, DateTime updateDate, DateTime insertDate, DateTime? deleteDate)
{
RowGUID = rowGuid;
InsertUserGUID = insertUserGuid;
UpdateUserGUID = updateUserGuid;
DeleteUserGUID = deleteUserGuid;
UpdateDate = updateDate;
InsertDate = insertDate;
DeleteDate = deleteDate;
}
[UIHint("AuditTrail")]
public string AuditTrail
{
get
{
...code to produce readable user audit strings
return auditTrail;
}
}
...additional methods
}
In another class
public partial class SomeModel
{
private CommonAttributesBase _common;
public CommonAttributesBase Common
{
get
{
if (_common == null)
{
_common = new CommonAttributesBase { AllowNotes = true, AllowAttachments = true, RowGUID = RowGUID };
_common.SetAuditProperties(RowGUID, InsertUserGUID, UpdateUserGUID, DeleteUserGUID, UpdateDate, InsertDate, DeleteDate);
}
return _common;
}
set
{
_common = value;
}
}
...rest of model
}
For me, I prefer to use different interfaces for each type (audit or note), and use decorator to retrieve those related data, instead of embedding those in the common class:
public class Note
{
//Node properties
}
public class AuditTrail
{
//Audit trail properties
}
public interface IAuditable
{
AuditTrail AuditTrail { get; set; }
}
public interface IHaveNotes
{
IList<Note> Notes { get; set; }
}
public class SomeModel : IAuditable, IHaveNotes
{
public IList<Note> Notes { get; set; }
public AuditTrail AuditTrail { get; set; }
public SomeModel()
{
Notes = new List<Note>();
}
}
public class AuditRepository : IRepository<T> where T : IAuditable
{
private IRepository<T> _decorated;
public AuditRepository(IRepository<T> decorated)
{
_decorated = decorated;
}
public T Find(int id)
{
var model = _decorated.Find(id);
model.Audit = //Access database to get audit
return model;
}
//Other methods
}
public class NoteRepository : IRepository<T> where T : IHaveNotes
{
private IRepository<T> _decorated;
public NoteRepository(IRepository<T> decorated)
{
_decorated = decorated;
}
public T Find(int id)
{
var model = _decorated.Find(id);
model.Notes = //Access database to get notes
return model;
}
//Other methods
}
Advantages is that the client will be able to choose to load audit/note or not, the logic of audit and note are also separated from the main entity repository.
What you're doing is basically composition. As others have stated, there's many ways to accomplish what you're looking for, some better than others, but each method depends on the needs of your application, of which only you can speak to.
Composition
Composition involves objects having other objects. For example, if you were going to model a car, you might have something like:
public class Car
{
public Engine Engine { get; set; }
}
public class Engine
{
public int Horsepower { get; set; }
}
The benefit to this approach is that your Car ends up with a Horsepower property via Engine, but there's no inheritance chain. In other words, your Car class is free to inherit from another class while not effecting this property or similar properties. The problems with this approach is that you have to involve a separate object, which in normally is not too troubling, but when combined when tied back to a database, you're now talking about having a foreign key to another table, which you'll have to join in order to get all the class' properties.
Entity Framework allows you to somewhat mitigate this effect by using what it calls "complex types".
[ComplexType]
public class Engine
{
...
}
The properties of complex types are mapped onto the table for the main class, so no joins are involved. However, because of this, complex types have certain limitations. Namely, they cannot contain navigation properties -- only scalar properties. Also, you need to take care to instantiate the complex type or you can run into problems. For example, any nulled navigation property is not validated by the modelbinder, but if you have a property on your complex type that is required (which results in a property on your main class' table that is non-nullable), and you save your main class while the complex type property is null, you'll get an insertion error from the database. To be safe you should always do something like:
public class Car
{
public Car()
{
Engine = new Engine();
}
}
Or,
public class Car
{
private Engine engine;
public Engine Engine
{
get
{
if (engine == null)
{
engine = new Engine();
}
return engine;
}
set { engine = value; }
}
}
Inheritance
Inheritance involves deriving your class from a base class and thereby getting all the members of that base class. It's the most straight-forward approach, but also the most limiting. This is mostly because all of the .NET family of languages only allow single inheritance. For example:
public class Flyer
{
public int WingSpan { get; set; }
}
public class Walker
{
public int NumberOfLegs { get; set; }
}
public class Swimmer
{
public bool HasFlippers { get; set; }
}
public class Duck : ????
{
...
}
That's a bit contrived, but the point is that Duck is all of a Flyer, Walker and Swimmer, but it can only inherit from one of these. You have to be careful when using inheritance in languages that only allow single inheritance to make sure that what you inherit from is the most complete base class possible, because you won't be able to easily diverge from this.
Interfaces
Using interfaces is somewhat similar to inheritance, but with the added benefit that you can implement multiple interfaces. However, the downside is that the actual implementation is not inherited. In the previous example with the duck, you could do:
public class Duck : IFlyer, IWalker, ISwimmer
However, you would be responsible for implementing all the members of those interfaces on your Duck class manually, whereas with inheritance they just come through the base class.
A neat trick with interfaces and .NET's ability to extend things is that you can do interface extensions. These won't help you with things like properties, but you can move off the implementation of some of the class' methods. For example:
public static class IFlyerExtensions
{
public static string Fly(this IFlyer flyer)
{
return "I'm flying";
}
}
Then,
var duck = new Duck();
Console.WriteLine(duck.Fly());
Just by implementing IFlyer, Duck gets a Fly method, because IFlyer was extended with that method. Again, this doesn't solve every problem, but it does allow interfaces to be somewhat more flexible.
There's a couple different ways you could do something like this. I personally haven't worked with EF so I can't speak in regards to how it will work.
Option One: Interfaces
public interface IAuditable
{
Guid RowGUID { get; }
Guid InsertUserGUID { get; }
Guid UpdateUserGUID { get; }
Guid DeleteUserGUID { get; }
DateTime UpdateDate { get; }
DateTime InsertDate { get; }
DateTime DeleteDate { get; }
}
Of course you can change it to get and set if your use cases need that.
Option Two: Super/base classes
public abstract class AuditableBase
{
// Feel free to modify the access modifiers of the get/set and even the properties themselves to fit your use case.
public Guid RowGUID { get; set;}
public Guid InsertUserGUID { get; set;}
public Guid UpdateUserGUID { get; set;}
public Guid DeleteUserGUID { get; set;}
public DateTime UpdateDate { get; set;}
public DateTime InsertDate { get; set;}
public DateTime DeleteDate { get; set;}
// Don't forget a protected constructor if you need it!
}
public class SomeModel : AuditableBase { } // This has all of the properties and methods of the AuditableBase class.
The problem with this is that if you cannot inherit multiple base classes, but you can implement multiple interfaces.

automapper: skipping/ignoring nested types

I'm trying to create a map between a domain object and viewmodel to support a use case that feels quite common. The fact that I can't find a solution makes me think I'm approaching the problem incorrectly. Here's some psuedo code that represents my source and destination types:
public class DomainClass
{
public NestedDomainClass1 NestedDomainClass1{ get; set; }
}
public class NestedDomainClass1
{
public NestedDomainClass2 NestedDomainClass2 { get; set; }
}
public class NestedDomainClass2
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
public class DomainViewModel
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
As you can see, DomainViewModel maps perfectly to DomainClass.NestedDomainClass1.NestedDomainClass2. However, for reasons that aren't entirely relevant, I can't simply create a mapping at that level. Instead I have to map two levels higher:
Mapper.CreateMap<DomainObj, DomainViewModel>();
This is unfortunate, as the minute I do this, I can no longer rely on AutoMapper conventions to automagically map similarly named properties, and I end having to write a lot of highly repetitive code:
Mapper.CreateMap<DomainClass, DomainViewModel>().ForMember(dest=>dest.PropertyA, opt=>opt.MapFrom(source=>source.NestedDomainClass1.NestedDomainClass2.PropertyA));
Mapper.CreateMap<DomainClass, DomainViewModel>().ForMember(dest=>dest.PropertyB, opt=>opt.MapFrom(source=>source.NestedDomainClass1.NestedDomainClass2.PropertyB));
I've played with the RecognizeDestinationPrefixes and RecognizeDestinationPostfixes methods in the hopes of getting AutoMapper to "skip" directly to the property I'd like to map from (NestedDomainClass2), but no luck. Any help would be appreciated!
That's because you're trying map between two completely different types. You really need to do something like this:
Mapper.CreateMap<NestedDomainClass2, DomainViewModel>();
Mapper.AssertConfigurationIsValid();
var dvm = Mapper.Map<NestedDomainClass2, DomainViewModel>
(obj.NestedDomainClass1.NestedDomainClass2);
However if you want to, you can hide that detail by defining a TypeConverter. Something like this should work:
public class DomainTypeConverter : TypeConverter<DomainClass, DomainViewModel>
{
protected override DomainViewModel ConvertCore(DomainClass source)
{
return Mapper.Map<NestedDomainClass2, DomainViewModel>
(source.NestedDomainClass1.NestedDomainClass2);
}
}
You can then define your mapping to be something like this:
Mapper.CreateMap<NestedDomainClass2, DomainViewModel>();
Mapper.CreateMap<DomainClass, DomainViewModel>()
.ConvertUsing(new DomainTypeConverter());
Mapper.AssertConfigurationIsValid();
And use it like this:
var dvm = Mapper.Map<DomainClass, DomainViewModel>(dc);

Categories

Resources