entity framework unidirectional association from one to many - c#

I have an Account class which will be used to indicate who is responsible for a certain entity. There will be many entities where this will be used, so I don't want to pollute my Account class with all these collections
public class Account
{
public Guid Id{get; set;}
public Guid Name{get; set;}
...
public class EntityConfiguration : EntityConfigurationBase<Account>
{
public EntityConfiguration()
{
// I do not want these!
HasMany(a => a.As)
.WithOptional(x => x.Account)
.HasForeignKey(x =>x.AccountKey);
}
}
}
}
public class A
{
public Guid Id {get; set;}
public Account Account{get; set;}
// FK-Nav property
public Guid AccountKey{get;set;}
public class EntityConfiguration : EntityConfigurationBase<A>
{
public EntityConfiguration()
{
// what should go here to specify the association to Account?
????
}
}
}
public class B
{
public Guid Id {get; set;}
public Account Account{get; set;}
// FK-Nav property
public Guid AccountKey{get;set;}
public class EntityConfiguration : EntityConfigurationBase<B>
{
public EntityConfiguration()
{
// what should go here to specify the association to Account?
????
}
}
}
etc.

public class A
{
public Guid Id {get; set;}
public Account Account{get; set;}
// FK-Nav property
public Guid AccountKey{get;set;}
public class EntityConfiguration : EntityConfigurationBase<A>
{
public EntityConfiguration()
{
HasOptional(x => x.Account).HasMany().HasForeignKey(x=>x.AccountKey);
}
}
}

Related

AutoMapper with nested objects and container class

I'm developing an API with .NET core and using AutoMapper.
all the API responses will be wrapped with a data element in the JSON response like below example
GET User
{
"data" {
"id" : 1,
"user_name": "abc"
"countryr" : {
"id" : 1348,
"code" : "USA"
}
}
}
So we have an entity for User and Country
public partial class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public virtual Country country { get; set; }
}
public partial class Country
{
public int Id { get; set; }
public string Code{ get; set; }
}
To map entities to DTO we have below reponseDTO
public class GetUserDTO {
public User data {get; set;} // To wrap reponse with data
}
public class UserDto {
public int id {get; set;}
public String user_name {get; set;}
public Country country {get; set;}
}
public class CountryDto {
public int id {get; set;}
public String code {get; set;}
}
As per my understanding , I should map the entity User to the UserDTO and Country entity to CountryDTO but what about GetUserDTO class itself? it basically contains other entities so the class itself cannot be mapped to anything it acts like a container.
So below what I did so far which is not correct
public class UserProfile : AutoMapper.Profile
{
public MappingProfile()
{
CreateMap<User, GetUserDTO>();
CreateMap<User, UserDto>()
.ForMember(userDto => userDto.user_name, map => map.MapFrom(user => user.FirstName))
CreateMap<Country, CountryDto>();
}
}
Json response
{
"data" : null
}
What to do for such situations?
You should not refer your entity classes in your DTO classes. You might want to change the DTO as below.
public class GetUserDTO {
public UserDto data {get; set;} // To wrap reponse with data
}
public class UserDto {
public int id {get; set;}
public string user_name {get; set;}
public CountryDto country {get; set;}
}
public class CountryDto {
public int id {get; set;}
public string code {get; set;}
}
And then in the Mapper profile, you need to explicitly map each property as cases are different(AutoMapper will map without explicity map if the names are exactly the same. In your example, there is a case difference)
And then remove the below line from the MapperProfile as there is no mapping from the User class to GetUserDTO class. This is the reason you are not getting any output.
CreateMap<User, GetUserDTO>();
While getting the data, you should create a new instance of GetUserDTO class and set the property "data" from the result of mappaing of the User object.
This will get you the output.

How to update an entity with a collection of abstract types by using GraphDiff?

I have some models:
public class RootEntity
{
public int Id {get; set;}
public virtual ICollection<AbstractEntity> CollectionA {get; set;}
}
public abstract class AbstractEntity
{
public int Id {get; set;}
}
public class DerivedEntityA : AbstractEntity
{
public virtual ICollection<AnotherType> CollectionB {get; set;}
}
public class DerivedEntityB : AbstractEntity
{
public string Name {get; set;}
}
The relationships of above models are like this:
RootEntity ---> ICollection<AbstractEntity>
┗━━ DerivedEntityA ---> ICollection<AnotherType>
┗━━ DerivedEntityB
---> has a
┗━━ derived from
Now I want to update a RootEntity entity named rootEntity by using GraphDiff:
context.UpdateGraph(rootEntity, map => map
.OwnedCollection(r => r.CollectionA, with => with
.OwnedCollection(de => de.CollectionB) // this doesn't work because 'de' doesn't have 'CollectionB'
)
);
So how can I update it properly?

Entity Framework Include Record with certain value in a Navigation Property

I am using Entity Framework 6 Code First and I'm configuring the mapping of my domain model with Fluent API. I don't see how to create a navigation properties for a Table which is a little tricky.
I have several objects which can make noise, I would like to record that noise in a NoiseRecord Table.
I need some kind of conditional mapping, something like that :
modelBuilder.Entity<NoiseRecord>().HasRequired(n=>n.Origine.OrigineType()=="Car").WithMany(c=>c.NoiseRecords);
That would be the mapping of the Car Navigation Property to avoid that, for example, it includes record related to Planes.
Here is my code
public interface INoisy
{
int ID {get; set;}
string OriginType()
...
//And other useful things not related to persistence
}
public class Car : INoisy
{
...
ICollection<NoiseRecord> NoiseRecords { get; set; }
string OrigineType()
{
return "Car";
}
}
public class Plane : INoisy
{
...
ICollection<NoiseRecord> NoiseRecords {get; set;}
string OrigineType()
{
return "Plane";
}
}
And a couple of other classes implement INoisy also.
Below is the NoiseRecord Table.
public class NoiseRecord
{
public int RecordID {get; set;}
public INoisy NoiseOrigine {get; set;}
public double NoiseMagnitude {get; set;}
}
I'm looking for a way to achieve that with Fluent API.
Thank you !
First of all, it is not possible to use interfaces as navigation properties. But you could use an abstract base class for your noise origins
public abstract class NoiseOrigin
{
public NoiseOrigin()
{
this.NoiseRecords = new Collection<NoiseRecord>();
}
public int Id { get; set; }
public ICollection<NoiseRecord> NoiseRecords { get; set; }
}
public class Car : NoiseOrigin {}
public class Plane : NoiseOrigin { }
public class NoiseRecord
{
public int Id { get; set; }
public int OriginId { get; set; }
public NoiseOrigin Origin { get; set; }
public double NoiseMagnitude { get; set; }
}
Your fluent API mapping whould look like this
public class NoiseModelContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Car>().Map(p => p.Requires("Type").HasValue("Car"));
modelBuilder.Entity<Plane>().Map(p => p.Requires("Type").HasValue("Plane"));
}
public DbSet<NoiseOrigin> NoiseOrigins { get; set; }
public DbSet<NoiseRecord> NoiseRecords { get; set; }
}
To get all car noise records your query will look like
using (var db = new NoiseModelContext()) {
var records = db.NoiseRecords.Where(p => p.Origin is Car);
// or like this - the result is the same.
var records2 = db.NoiseOrigins.OfType<Car>().SelectMany(p => p.NoiseRecords);
}

entity -> interface relationship, how to map

I’m trying to develop some basic web app. I will post question with only two entities Article and Image.
One article has many images, and one or more images belong to only one article.
Every article implements interface IArticle and abstract class ArticleBase. ArticleBase defines only common properties for each article but child articles can have more properties beside those defined in ArticleBase.
So I have (IArticle, ArticleBase, ArticleComputer, ArticleCar)
public abstract class ArticleBase : Entity, IArticle
{
...
public string Name { get; set; }
public DateTime Created { get; set; }
}
public class ArticleComputer : ArticleBase
{
public virtual IList<Image> Images {get; set;}
public virtual OSTypeEnum OS {get; set;}
...
}
public class ArticleCar : ArticleBase
{
public IList<Image> Images {get;set;}
public virtual EngineTypeEnum EngineType {get; set;}
...
}
public class Image : Entity<Guid>
{
public virtual IArticle Article {get; set;}
}
So my question would be: how should I map Image object since I do not want to map every Article which implements IArticle independently?
public class ImageMap : ClassMapping<Image>{
public ImageMap() {
Id(x => x.Id, m => m.Generator(Generators.Identity));
ManyToOne(x => x.Article, m =>
{
m.NotNullable(true);
});
}
}
Why not create an interim abstract class
public abstract class ImageArticle : ArticleBase
{
public virtual IList<Image> Images { get; protected set; }
}
So ComputerArticle : ImageArticle, etc and Image becomes:
public class Image : Entity<Guid>
{
public virtual ImageArticle Article { get; set; }
}
And map: (I normally use Fluent NHibernate so apologies if this is the incorrect syntax)
public class ImageArticleMapping : SubclassMapping<ImageArticle>
{
public ImageArticleMapping()
{
this.Bag(x => x.Images)
}
}

How to create many-to-many relationship on the same entity?

For example I have Poduct entity:
public class Product : DatabaseEntity
{
public int Id {get; set;}
public int Name {get; set;}
public decimal Price {get; set;}
...
}
The idea is I want to create the editable collection of similar products for product. So it is like many-to-many but on the same entity - product So I updated my model like below:
public class Product : DatabaseEntity
{
public int Id {get; set;}
public int Name {get; set;}
public decimal Price {get; set;}
public ICollection<Product> SimilarProducts { get; private set; }
public void AddSimilar(Product product)
{
SimilarProducts.Add(product);
}
...
}
also I updated my DbContext class:
modelBuilder.Entity<Product>()
.HasMany(p => p.SimilarProducts)
.WithOptional()
.WillCascadeOnDelete(false);
implemented edit product action:
public ActionResult Edit(ProductEditModel productEditModel)
{
if(!string.IsNullOrEmpty(productEditModel.SelectedSimilarProductLinkName))
{
var similarProduct = _productRepository.GetProduct(productEditModel.SelectedSimilarProductId);
product.AddSimilar(similarProduct);
}
_productRepository.AddProduct(product);
}
void IProductRepository.AddProduct(Product product);
public void AddProduct(Product product)
{
_repository.InsertOrUpdate(product);
}
But I get strange results: To product was added Product_Id field in my database and there is no such as ProductProduct table or something like that which stores related products ids as in usual many to many entities implementations. How can I create this table manually? What am I missing or what am doing wrong?
Thanks Swell for advice, I've already figured out the solution:
Model:
public class Product : DatabaseEntity
{
public int Id {get; set;}
public int Name {get; set;}
public decimal Price {get; set;}
public ICollection<Product> ParentSimilars { get; set; }
public ICollection<Product> ChildSimilars { get; set; }
[NotMapped]
public IEnumerable<Product> SimilarProducts
{
get
{
return ChildSimilars.Concat(ParentSimilars);
}
}
...
}
DbContext setup:
modelBuilder.Entity<Product>()
.HasMany(p => p.ChildSimilars)
.WithMany(p => p.ParentSimilars)
.Map(m =>
{
m.MapLeftKey("Product_Id");
m.MapRightKey("SimilarProduct_Id");
});
That's, basically, all.

Categories

Resources