How do I create a navigation property that can navigate to more than one entity type? - entity-framework-5

I have the following in my domain classes ( simplified )
public enum JobType
{
SalesOrder = 1,
StockOrder = 2
}
public class SalesOrder : LoggedEntity
{
public string Name { get; set; } // and other fields
}
public class StockOrder : LoggedEntity
{
public string Name { get; set; } // and other fields
}
public class Job : LoggedEntity
{
public int JobType { get; set; } // jobtype enum
public virtual LoggedEntity LinkedEntity { get; set; }
}
My context is as follows;
public class Context : DbContext
{
public DbSet<Job> Jobs { get; set; }
public DbSet<StockOrder> StockOrders { get; set; }
public DbSet<SalesOrder> SalesOrders { get; set; }
}
When I run the migration i get the error described [here][1] So using an abstract entity appears not to work.
My question was, how do I create a navigation property that can navigate to more than one entity type?
If JobType = SalesOrder then I want to navigate to sales order, if JobType = StockOrder then I want to navigate to stock order.
I wanted to use a Table Per Heirarchy Strategy [see TPH here][2]

The trick is to keep EF oblivious of the LoggedEntity class. Remodel your entities according to this example:
public enum JobType
{
SalesOrder = 1,
StockOrder = 2
}
public abstract class LoggedEntity
{
public int Id { get; set; }
public string Name { get; set; } // and other fields
}
public abstract class BaseOrder : LoggedEntity // New base class for orders!!
{ }
public class SalesOrder : BaseOrder
{ }
public class StockOrder : BaseOrder
{ }
public class Job : LoggedEntity
{
public JobType JobType { get; set; } // jobtype enum
public virtual BaseOrder Order { get; set; }
}
public class Tph2Context : DbContext
{
public DbSet<Job> Jobs { get; set; }
public DbSet<BaseOrder> Orders { get; set; }
}
You will see that the migration creates two tables, Jobs and BaseOrders (name to be improved). Job now has a property Order that can either be a SalesOrder or a StockOrder.
You can query specific Order types by
contex.Orders.OfType<StockOrder>()
And you will notice that EF doesn't know LoggedEntity, because
context.Set<LoggedEntity>()
will throw an exception
The entity type LoggedEntity is not part of the model for the current context.

how do I create a navigation property that can navigate
to more than one entity type?
You cannot do so. atleast not now. navigational properties are way of describing relationship between entities. at most, they represent, some sort of sql relationship. so you cannot alter or define such a relationship on the fly. you have to define it before hand.
Now in order to do that, you have to define separate navigational property for your separate conditions i.e.
public class Job : LoggedEntity
{
public int JobTypeSales { get; set; }
public int JobTypeStock { get; set; }
public virtual SalesOrder SalesOrder { get; set; }
public virtual StockOrder StockOrder { get; set; }
}
and then link them in configuration in modelbuilder through fluent API.
HasRequired(s => s.SalesOrder)
.WithMany()
.HasForeignKey(s => s.JobTypeSales).WillCascadeOnDelete(true);
HasRequired(s => s.StockOrder)
.WithMany()
.HasForeignKey(s => s.JobTypeStock).WillCascadeOnDelete(true);
and
as for your error "Sequence Contains No Elements"
this error comes, when the Linq query that you specified, is using either .First() or .Single(), or .ToList() and query returned no data.
so to avoid it use, .FirstOrDefault() or SingleOrDefault().
obviously with proper null check.

Related

Servicestck.Ormlite equivalent of .include

Given the following example POCOS:
public class Order
{
[AutoIncrement]
public int Id { get; set; }
...
[Reference]
public List<Item> Items { get; set; }
}
public class Item
{
[AutoIncrement]
public int Id { get; set; }
....
}
Is there a way to select a set of Orders and include their related items? Akin to a .include() in Entity Framework.
In terms of Service Stack API, a multi-entity version of LoadSingleById() which does eagerly load referenced fields.

Why does this ploymorphic List property go null when adding additional objects to the list?

Consider the following:
public class VideoContainer<T>
{
public string Name { get; set; }
//public List<VideoContainer<T>> VideoContainers { get; set; }
}
public class Perspective : VideoContainer<Perspective>
{
public List<VideoContainer<SourceContainer>> VideoContainers { get; set; }
}
I want to ensure VideoContainer<Perspective>.VideoContainers can only contain VideoContainer<SourceContainer> types.
I add a new Perspective object to a List<Perspective> with three VideoContainers. The problem is that when I add a new Perspective to the list, the previously-added Perspective.VideoContainers is null.
Why is this happening?
It sounds like you need two generic types:
public class VideoContainer<T, U>
{
public string Name { get; set; }
public List<VideoContainer<U>> VideoContainers { get; set; }
}
public class Perspective : VideoContainer<Perspective, SourceContainer>
{
// No longer declare the list, just use it... it's now:
// public List<VideoContainer<SourceContainer>> VideoContainers { get; set; }
}

DDD/CQRS, Entity has access to Query, Command?

public class PageRoleService
{
public void SetRoles(Page page, User activeUser)
{
var rb = page.Project.ProjectType.GetRoleFor(activeUser.UserType);
page.RolesForPage.Add(activeUser, rb);
var managers = GetAllManagersOf(activeUser);
foreach (var m in managers)
{
page.RolesForPage.Add(m, rb);
}
}
}
public class Project : Entity
{
public ProjectType ProjectType { get; set; }
public IList<Page> Pages { get; set; }
}
public class Page : Entity
{
public string Name { get; set; }
public Project Project { get; set; }
public IDictionary<User, RoleBehaviour> RolesForPage { get; set; }
}
public class ProjectType : Entity
{
public IQueryProcessor QueryProcessor { get; set; }
public IList<RoleBehaviour> RoleBehaviours { get; set; }
public RoleBehaviour GetRoleFor(USerType userType)
{
var behaviour = return QueryProcessor.Execute(new GetRolesByUserAndProjectTypeQuery() {
ProjectType = this,
UserType = userType
});
// Filter behaviour attributes for project type properties, business rules, etc...
// FilterBehaviour(behaviour);
return behaviour;
}
}
public class GetRolesByUserAndProjectTypeQuery
{
public UserType UserType { get; set; }
public ProjectType ProjectType { get; set; }
}
public class GetRolesByUserAndProjectTypeQueryHandler
{
public Db Db { get; set; }
public RoleBehaviour Execute(GetRolesByUserAndProjectTypeQuery query)
{
return Db.FirstOrDefault(r => r.UserType == query.UserType && r.ProjectType == query.projectType);
}
}
public class RoleBehaviour : Entity
{
public Role ROleForArea1 { get; set; }
public Role ROleForArea2 { get; set; }
public UserType UserType { get; set; }
public ProjectType ProjectType { get; set; }
public IDictionary<string, string> Attributes { get; set; }
}
public enum UserType
{
A,
B,
C,
D
}
public class Role : Entity
{
public IList<string> Permissions { get; set; }
}
I don't use repository, no need data abstraction, I use CQRS for crud operations. (CreateProjectCommand, GetRolesByUserAndProjectTypeQuery, etc..)
Users related a lot of project and page. Users have more than role for each Page Entity and is dynamically created when user (client) request to fetch All projects page or single page item.
My Page Role Service determinates page roles for active user and its managers. My MVC Controller use PageRoleService.
PageRoleService is Application Service or Domain Service or .....?
QueryProcessor in Entity (ProjectType) is invalid approach? How can handle this/their problems without lazy or eager loading?
RoleBehaviour is Entity or Value Object?
PageRoleService is a service or business logic in domain?
I know that I'm some years later, but:
I would put away the base class Entity, because it looks that this are just Dtos returned by the queryhandler (infact GetRolesByUserAndProjectTypeQueryHandler.Execute returns a RoleBehaviour).
Given this, I think that:
PageRoleService is a simple service that completes a Dto, hence it looks a kind of factory
Given that ProjectType here has two different roles (a Dto and Entity, and this is against CQRS), if:
it's a Dto, then use a service/factory/ORM to load extra data on it
it's an Entity, try to load all the data that's needed by it. This because there're great changes that you'll need it on the way to execute your command (great explanation about DDD and entities).
The object has it's own identity? Has it an Id that, even if things will change, remains the same? Looking at it, it looks just a Dto, with nothing really interesting (at business level).
see 1.

Using Entity Framework 5.0 map relationship between parent and children when ID are Guids with newsequentialid()

I have two classes with a one to many relationship.
public partial class Client
{
public Client()
{
this.Client_Local = new HashSet<Client_Local>();
}
public System.Guid Guid { get; set; }
public string Name { get; set; }
public virtual ICollection<Client_Local> Client_Local { get; set; }
}
public partial class Client_Local
{
public System.Guid LocalGuid { get; set; }
public System.Guid Guid { get; set; }
public string CultureID { get; set; }
public string LocalName { get; set; }
public virtual Client Client { get; set; }
}
The mapping classes are:
class ClientMapping : EntityTypeConfiguration<Client>
{
public ClientMapping()
{
this.HasKey(entity => entity.Guid); //As newsequentialid()
this.ToTable("Client");
this.Property(entity => entity.Guid).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
class Client_LocalMapping : EntityTypeConfiguration<Client_Local>
{
public Client_LocalMapping()
{
this.HasKey(entity => entity.LocalGuid); // as As newsequentialid()
this.ToTable("Client_Local");
this.Property(entity => entity.LocalGuid).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.HasRequired<Client>(e => e.Client).WithMany(p => p.Client_Locals).HasForeignKey<Guid>(c => c.Guid);
}
}
I can create new instances of client class and save them to the database successfully. But when I try and add a Client_Local class and save it to the database I get "A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'Guid'.".
The key fields are generated in sql as newsequentialid for performance reasons. And there is a foreign key relationship between Client_Local.Guid and Client.Guid.
Retrieving data from the database works with the above mapping classes. Any help would be greatly appreciated.

AutoMapper - How to map a concrete domain class to an inherited destination DTO class?

I have a flat domain class like this:
public class ProductDomain
{
public int ID { get; set; }
public string Manufacturer { get; set; }
public string Model { get; set; }
public string Description { get; set; }
public string Price { get; set; }
}
I have two DTO classes like this:
public class ProductInfoDTO
{
public int ID { get; set; }
public string Manufacturer { get; set; }
public string Model{ get; set; }
}
public class ProductDTO : ProductInfoDTO
{
public string Description { get; set; }
public string Price { get; set; }
}
Now the problem is:
Scenario #1:
Mapper.CreateMap<ProductDomain, ProductInfoDTO>() // this mapping works fine
Scenario #2:
Mapper.CreateMap<ProductDomain, ProductDTO>() // this mapping is not working and throws System.TypeInitializationException
So my question is how to create mapping between ProductDomain and ProductDTO (which inherits ProductInfoDTO) without breaking the definition of both source and destination classes. Also I dont want to introduce any new inheritance for the domain class ProductDomain.
Thanks
You can build your own custom TypeConverter like this
public class ProductDomainToProductDTOConverter : ITypeConverter<ProductDomain, ProductDTO>
{
public ProductDTO Convert(ProductDomain source)
{
ProductDTO product = new ProductDTO();
product.Price = source.Price;
...
return product;
}
}
And then create a map with your custom TypeConverter like this
Mapper.CreateMap<ProductDomain, ProductDTO>().ConvertUsing<ProductDomainToProductDTOConverter>();

Resources