ReferencesAny nhibernate mapping in entity framework? - mapping

I'm wondering how to create mapping in entity framework,
that is similar to ReferenceAny in fluent nhibernate.
What I got:
Entities:
public abstract class Document : Entity
{
public virtual ICollection<Feature> Features { get; set; }
}
public class DocumentA : Document
{
}
public class DocumentB : Document
{
}
public class Feature : Entity
{
public IEntity Super { get; set; }
public virtual string Value { get; set; }
}
In Feature mapping:
ReferencesAny(x => x.Super)
.EntityTypeColumn("type")
.EntityIdentifierColumn("super")
.AddMetaValue<DocumentA>("DoucmentA")
.AddMetaValue<DokumentB>("DocumentB")
.IdentityType<int>();
In DocumentA mapping:
HasMany<Feature>(x => x.Features)
.AsSet()
.Inverse()
.KeyColumn("super").Not.KeyNullable()
.Where("type = 'DocumentA'")
.Fetch.Join()
.Cascade.AllDeleteOrphan();
In DocumentB mapping:
HasMany<Feature>(x => x.Features)
.AsSet()
.Inverse()
.KeyColumn("super").Not.KeyNullable()
.Where("type = 'DocumentB'")
.Fetch.Join()
.Cascade.AllDeleteOrphan();
This kind of mapping gives me clean Features table with columns: id, value, type, super,
where type act as discriminator and super is document id.
How map this in EF to achieve Features table with same columns, since I can't change it?

Related

Entity Framework and Many-to-Many relationships, controlling the Intermediate table column names

I'm trying to wrap my head around a Many-to-Many relationship with Code-First mapping.
If I have an Album Class that can have many Genres (and vice-versa), I understand that I need to have an Intermediate table and Entity Framework will automatically do that for me. However, I would like a little more control over the Intermediate table, so I am creating one myself, the main reason is that I would like to be able to mark the row as deleted from the front-end and leave it in the database.
To do this for all my Classes I have created a BaseObject that they are Inherit from (I've removed many of the Annotations and other code to simplify this post):
public class BaseObject
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Oid { get; set;
public DateTime DateCreated { get; set; }
public bool IsDeleted { get; set; }
public DateTime? DeletedDate { get; set; }
}
After that we have the Albums and Genres Classes:
public class Album : BaseObject
{
public string Name { get; set; }
public virtual List<AlbumsGenres> Albums { get; set; }
}
public class Genre : BaseObject
{
public string Name { get; set; }
public virtual List<AlbumsGenres> Genres { get; set; }
}
Finally the AlbumsGenres Intermediate Class:
public class AlbumsGenres : BaseObject
{
// Left blank because EF will create "Album_Oid" and "Genre_Oid" columns
// Tried the below code, but EF still created it's own Columns
/*
public Guid Album { get; set; }
public Guid Genre { get; set; }
*/
}
The questions that I have; Is there a way to tell EF to create Album_Oid with a different Column Name like Album?
I would accept an answer of "Just don't worry about it", if a brief explanation (or link) was provided.
You can control the intermediate table, Normally I use explicit mapping but the following works with CodeFirst:
In Album, you want a List<Genre> (not AlbumGenre)
In Genre, you want a List<Album>
In your context, add the following override for OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Album>()
.HasMany(a => a.Genres)
.WithMany(g => g.Albums)
.Map(x =>
{
x.MapLeftKey("AlbumId");
x.MapRightKey("GenreId");
x.ToTable("AlbumGenres");
});
base.OnModelCreating(modelBuilder);
}

AutoMapper mapping base class and projection

How do I map this:
public class Domain_1
{
public DomainType DomainType { get; set; }
public Domain_2 Domain2 { get; set; }
public Domain_3 Domain3 { get; set; }
}
to:
public abstract class DTOBase
{
// properties from Domain_1
}
public class DTO_1 : DTOBase
{
// properties from Domain_2
}
public class DTO_2 : DTOBase
{
// properties from Domain_3
}
Ideally,the Domain design should be same as the DTO but I can't due to EF6 and existing database restrictions.
Currently what I have right now is:
this.CreateMap<Domain_1, DTOBase>()
.ConstructUsing(SomeDTOCreatorFactoryMethod);
this.CreateMap<Domain_2, DTO_1>();
What SomeDTOCreatorFactoryMethod does is it creates the DTO based on the DomainType.
This works fine but I wanted to do some projection something like:
var domain_Db = dbContext.Domain1.Where(d => d.Id == 1).ProjectTo<DTOBase>.SingleOrDefault();
// var result = _mapper.Map<Domain1, DTOBase>(domain_Db);
Its throwing an error that cannot instantiate an abstract class. I understand the error but how I can use the factory method in order to create the DTO?
And what if I have to use a custom resolver on certain properties? I know this is not supported but is there a workaround?

Entity Framework One to Optional One relationship

I've been trying to figure out how to create a one to optional one relationship in Entity Framework but everything I try seems to result in an exception or with the navigation properties not working correctly. Could anyone explain how to annotate the below so both objects can exist in the database and a link can optionally be made from one to the other?
Many thanks
public class ObjectA
{
public int ID { get; set; }
public virtual ObjectB ObjectB { get; set; }
}
public class ObjectB
{
public int ID { get; set; }
public virtual ObjectA ObjectA { get; set; }
public int? ObjectAID { get; set; }
}
Edit:
With the code as it stands I get the following exception:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code
Additional information: Unable to determine the principal end of an association between the types 'Namespace.ObjectA' and 'Namespace.ObjectB'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
You need to choose which entity will be a principal and which will be a dependent in this relationship. If it's true that ObjectB is dependent, then you could solve the problem with the following options:
1) Data Annotations. Mark ObjectB's ObjectAID property with RequiredAttribute:
public class ObjectB
{
public int ID { get; set; }
public virtual ObjectA ObjectA { get; set; }
[Required]
public int? ObjectAID { get; set; }
}
2) Fluent API. Configure Model Builder:
public class AppDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ObjectB>().HasRequired(b => b.ObjectA).WithOptional(a => a.ObjectB);
}
}

How to render values in a view from Discriminator column in ASP.NET MVC 5?

Simple question - is there a way to render values from Discriminator column in my db? I have inheritance in my model and there is a Discriminator column but it's not accessible from any view like other columns. The model is generated by code-first and EF6.
You can use SqlQuery<T>, where T is a derived type of base class that is not an EF entity [NotMapped].
public abstract class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
[NotMapped]
public class PersonVm : Person
{
public string Discriminator { get; set; }
}
public class AppContext : DbContext
{
public DbSet<Person> People { get; set; }
}
And use it like this.
var q = db.People.Where(x => x.Name == "Foo").ToString();
var people = db.Database.SqlQuery<PersonVm>(q).ToArray();
// var here = people[0].Discriminator;

MVC How to map from my domain model to a specific view model

I'm getting started with the concept of mapping domain models to view models in ASP.NET MVC after watching a recommendation to do this to pass specific viewModels to the views.
I've been able to manage a basic mapping of one domain model to a simpler viewmodel with less properties but now need to produce a more complex viewmodel and can't figure it out. I have the following domain models
public class Club
{
public int ClubID { get; set; }
public string FullName { get; set; }
public string Description { get; set; }
public string Telephone { get; set; }
public string URL { get; set; }
public DateTime CreatedDate { get; set; }
public virtual ICollection<Member> Members{ get; set; }
}
public class Member
{
public int MemberID{ get; set; }
public string Name { get; set; }
public MemberType Membership{ get; set; }
public virtual Club Club { get; set; }
public virtual int ClubID { get; set; }
}
public enum MemberType
{
Standard,
Special,
Limited
}
I want to map to a view model such as this (note: I've split it like this because I think it makes sense but I'm not sure)...
public class ClubDetailsViewModel
{
public int ClubID { get; set; }
public string FullName { get; set; }
public string Description { get; set; }
public IList<ClubDetailsMemberSummaryViewModel> Members { get; set; }
}
public class ClubDetailsMemberSummaryViewModel
{
public MemberType Membership { get; set; }
public int MemberCount { get; set; }
}
What I'm trying to end up with is a page which displays some of the club details plus a summary report of the member types at the club with a count of the members. Such as:
Some Club Name
Description of the club.....
CLUB MEMBERS
Limited - 15
Standard - 100
So I think the viewmodel makes sense for this (although might be a better way to do it). Where I'm struggling is how to map the elements. I can get the Club to map the main fields to the club viewmodel but really can't work out how to map the result of the list of clubs onto their view model and then add that to the main view model as a list.
I'm getting the clubs from my repository using this
var clubs = _clubRepository.GetClubByID(ID);
Then I can transform the Courts which are returned using an include in the data access layer from entity framework using this
var grpCourts = from c in clubs.Members
group c by c.Membership into grp
select new { st = grp.Key, count = grp.Distinct().Count() };
How would I loop through the resulting records and map those to the ClubDetailsMemberSummaryViewModel and then add the list of those to the main ClubDetailsViewModel?
Your mapping from Club to ClubDetailsViewModel will be trivial with the exception of Members. For that property, you could write a quick resolver inline or write your own custom resolver. An inline resolver would look something like this:
Mapper.CreateMap<Club, ClubDetailsViewModel>()
.ForMember(dest => dest.Members, opt => opt.ResolveUsing(src =>
{
return src.Members
.GroupBy(m => m.Membership)
.Select(grp => new ClubDetailsMemberSummaryViewModel
{
Membership = grp.Key,
MemberCount = grp.Distinct().Count()
});
}));
I think it's good practice to refactor more complex resolvers like this out to their own classes:
public class MembershipClubDetailsResolver : ValueResolver<Club, IList<ClubDetailsMemberSummaryViewModel>>
{
protected override IList<ClubDetailsMemberSummaryViewModel> ResolveCore (Club source)
{
return source.Members
.GroupBy (m => m.Membership)
.Select(grp => new ClubDetailsMemberSummaryViewModel
{
Membership = grp.Key,
MemberCount = grp.Distinct().Count()
})
.ToList();
}
}
And then use that resolver in your mapping:
Mapper.CreateMap<Club, ClubDetailsViewModel>()
.ForMember(dest => dest.Members, opt => opt.ResolveUsing<MembershipClubDetailsResolver>());
Your mapping appears to be rather complex, I think I would use the .ConvertUsing method of automapper
Mapper.CreateMap<List<Club>,List<ClubDetailsViewModel>>()
.ConvertUsing<ClubToClubDetailsViewModel>();
The conversion class has the following inheritance
public class ClubToClubDetailsViewModel: TypeConverter<List<Club>,List<ClubDetailsViewModel>>
{
....
}
Alternatively you can tinker with creating two "simple" mappings
Mapper.CreateMap<Club,ClubDetailsViewModel>()
That will map everything except the property called Members
Then you need to create a mapping for the members to ClubDetailsMemberSummaryViewModel, you can do that mapping manually or you can configure this in automapper aswell.
For more specific details on automapper you can visit https://github.com/AutoMapper/AutoMapper/wiki

Resources