I have two tables - master-detail with relation one-to-many.
Here are definitions and mappings:
public class Employee
{
public virtual int Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual IList<Project> Projects { get; set; }
public Employee()
{
Projects = new List<Project>();
}
}
public class Project
{
public virtual int Id { get; protected set; }
public virtual string Name { get; set; }
public virtual double EstimatedHours { get; set; }
public virtual Employee Employee { get; set; }
}
public EmployeeMap()
{
Id(x => x.Id);
Map(x => x.FirstName);
Map(x => x.LastName);
HasMany<Project>(x => x.Projects)
.KeyColumn("Id_emp")
.Cascade.All()
.Inverse()
.LazyLoad();
}
public ProjectMap()
{
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.EstimatedHours);
References(x => x.Employee).Class<Employee>().Columns("Id_emp").ForeignKey();
}
When I save data both employee and project tables are filled with data but in project table field Id_emp is null instead to have Id of employee.
What am I missing in mappings and referencing?
Related
I have an Item entity:
public class Item
{
public long Id { get; set; }
public string Name { get; set; }
public string Skuid { get; set; }
public double Price { get; set; }
public double Amount { get; set; }
}
And an Order entity:
public class Order
{
public long Id { get; set; }
public DateTime Date { get; set; }
public StatusEnum Status { get; set; }
public long SellerId { get; set; }
public Seller Seller { get; set; }
public double Total { get; set; }
public IList<Item> Items { get; set; }
}
My objective is to save the Order containing the items in the Database, but when the request is made, only the reference of my entity "Seller" is saved, but not the references of the items.
I did the following mapping on the "Order" entity:
public class OrderMap : IEntityTypeConfiguration<Order>
{
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.ToTable("Orders");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.ValueGeneratedOnAdd()
.UseIdentityColumn();
builder.Property(x => x.Date)
.IsRequired()
.HasColumnName("DateSale")
.HasColumnType("DATETIME")
.HasDefaultValueSql("GETDATE()");
builder.Property(x => x.Total)
.IsRequired()
.HasColumnName("Total")
.HasColumnType("DECIMAL");
builder.Property(x => x.Status)
.IsRequired()
.HasConversion(
v => v.ToString(),
v => (StatusEnum)Enum.Parse(typeof(StatusEnum), v))
.HasColumnName("Status")
.HasColumnType("NVARCHAR") //verificar se nao vai dar conflito
.HasMaxLength(120);
builder
.HasOne(x => x.Seller)
.WithOne()
.HasConstraintName("FK_Seller_Order")
.OnDelete(DeleteBehavior.Cascade);
builder
.HasMany(x => x.Items)
.WithOne()
.HasConstraintName("FK_Item_Order")
.IsRequired()
.OnDelete(DeleteBehavior.Cascade); //
}
}
What is the correct mapping to do?
Please first add these properties OrderId and Order to your Item entity class. This way you are instructions the framework to create an OrderId foreign key
column in the database.
public class Item
{
public long Id { get; set; }
public string Name { get; set; }
public string Skuid { get; set; }
public double Price { get; set; }
public double Amount { get; set; }
public long OrderId { get; set; }
public Order Order {get; set; }
}
And perhaps this part
builder.HasMany(x => x.Items).WithOne()
should be like this
builder.HasMany(x => x.Items).WithOne(x => x.Order)
Class Customer
public class Customer
{
public int Id { get; set; }
public int PersonId { get; set; }
public int DiscountValue { get; set; }
public Person Person { get; set; }
public ICollection<Receipt> Receipts { get; set; }
}
Class Person
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime BirthDate { get; set; }
}
Class CustomerModel
public class CustomerModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime BirthDate { get; set; }
public int DiscountValue { get; set; }
public ICollection<int> ReceiptsIds { get; set; }
}
I need to create mapping that combines Customer and Person into CustomerModel.
public class AutomapperProfile : Profile
{
public AutomapperProfile()
{
CreateMap<(Customer, Person), CustomerModel>();
}
}
How can I combine Customer and Person?
You can just map from Customer to CustomerModel as:
Solution 1: Specify the property mapping from source to destination via .ForMember().
CreateMap<Customer, CustomerModel>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Person.Name))
.ForMember(dest => dest.Surname, opt => opt.MapFrom(src => src.Person.Surname))
.ForMember(dest => dest.BirthDate, opt => opt.MapFrom(src => src.Person.BirthDate));
Solution 2: Flattening Person model via .IncludeMembers().
cfg.CreateMap<Customer, CustomerModel>()
.IncludeMembers(src => src.Person);
cfg.CreateMap<Person, CustomerModel>();
Demo Solution 1 & 2 # .NET Fiddle
I'm working with EF project and I try to add two foreign keys but I have a problem when I do Add Migration.
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public DateTime? DeathDate { get; set; }
public int? FatherId { get; set; }
public int? MotherId { get; set; }
[ForeignKey("FatherId")]
public virtual Person Father { get; set; }
[ForeignKey("MotherId")]
public virtual Person Mother { get; set; }
}
Add This code in your context
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOptional(a => a.Mother)
.WithMany()
.HasForeignKey(a => a.MotherId);
modelBuilder.Entity<Person>()
.HasOptional(a => a.Father)
.WithMany()
.HasForeignKey(a => a.FatherId);
}
```
I have a db schema along the lines of:
Product
ID
ProductName
Description
StoreBrand
ProductVariation
VariationID
ProductID
Size
StoreBrand
Price
Classes, predictably, look a bit like this:
public class Product
{
public virtual int ID { get; set; }
public virtual string ProductName { get; set; }
public virtual string Description { get; set; }
public virtual string StoreBrand { get; set; }
public virtual IEnumerable<ProductVariation> Variations { get; set; }
}
public class ProductVariation
{
public virtual int VariationID { get; set; }
public virtual int ProductID { get; set; }
public virtual Product Product {get; set;}
public virtual string Size { get; set; }
public virtual double Price { get; set; }
}
I've got the mapping classes like this:
public class ProductMapper : ClassMap<Product>
{
public ProductMapper()
{
Id(x => x.ID);
Map(x => x.ProductName);
Map(x => x.Description);
Map(x => x.StoreBrand);
HasMany(x => x.Variations)
.KeyColumn("ProductID");
}
}
public class ProductVariationMapper : ClassMap<ProductVariation>
{
public ProductVariation()
{
Id(x => x.ID);
Map(x => x.ProductID);
Map(x => x.Size);
Map(x => x.Price);
References(x => x.Product)
.Column("ProductID");
}
}
This is kind of working...
However, what I need to do is tie the Product.Brands together with the ProductVariation.Brands as well... (and vice versa)
So querying Product, returns a list of it's ProductVariations for that brand...
(Notice, ProductVariation doesn't have a property in the class, but it has the column for mapping)
ProductVariation.ID is non unique.
The key is ProductVariation.ID and ProductVariation.Brand (on the database)
public class Product
{
public virtual int ID { get; set; }
public virtual string StoreBrand { get; set; }
public virtual string ProductName { get; set; }
public virtual string Description { get; set; }
public virtual IEnumerable<ProductVariation> Variations { get; set; }
public override Equals(object obj)
{
return Equals(obj as Product)
}
public override Equals(Product other)
{
return (other != null) && (Id == other.Id) && (StoreBrand == other.StoreBrand);
}
public override GetHashCode()
{
unchecked
{
return Id.GetHashCode() * 397 + StoreBrand.GetHashCode();
}
}
}
public class ProductVariation
{
public virtual int ID { get; set; }
public virtual Product Product {get; set;}
public virtual string Size { get; set; }
public virtual double Price { get; set; }
}
public class ProductMapper : ClassMap<Product>
{
public ProductMapper()
{
// Id alone is not unique, hence compositeId
CompositeId()
.KeyProperty(x => x.ID)
.KeyProperty(x => x.StoreBrand);
Map(x => x.ProductName);
Map(x => x.Description);
HasMany(x => x.Variations)
.KeyColumn("ProductID", "StoreBrand");
}
}
public class ProductVariationMapper : ClassMap<ProductVariation>
{
public ProductVariation()
{
Id(x => x.ID);
Map(x => x.Size);
Map(x => x.Price);
References(x => x.Product)
.Column("ProductID", "StoreBrand");
}
}
Domain:
public class Account
{
public virtual int AccountId { get; set; }
public virtual int UserId { get; set; }
public virtual string HostName { get; set; }
public virtual DateTime CreatedOn { get; set; }
public virtual bool Deleted { get; set; }
}
public class Person
{
public Person()
{
PersonRoles = new List<PersonRole>();
}
public virtual int PersonId { get; set; }
public virtual Guid PersonGuid { get; set; }
public virtual string FirstName { get; set; }
public virtual string Surname { get; set; }
public virtual string Email { get; set; }
public virtual string Password { get; set; }
public virtual string SaltKey { get; set; }
public virtual int PersonType { get; set; }
public virtual DateTime CreatedOn { get; set; }
public virtual bool Deleted { get; set; }
public virtual bool Active { get; set; }
public virtual int? AccountId { get; set; }
public virtual ICollection<PersonRole> PersonRoles { get; private set; }
public virtual Account Account { get; set; }
}
Mapping:
public AccountMap()
{
Id(x => x.AccountId, "AccountId").Column("AccountId");
Map(x => x.UserId);
Map(x => x.HostName);
Map(x => x.CreatedOn);
Map(x => x.Deleted);
Table("crm_accounts");
}
public PersonMap()
{
Id(x => x.PersonId).Column("PersonId");
Map(x => x.PersonGuid);
Map(x => x.FirstName);
Map(x => x.Surname);
Map(x => x.Email);
Map(x => x.Password);
Map(x => x.SaltKey);
Map(x => x.PersonType);
Map(x => x.CreatedOn);
Map(x => x.Deleted);
Map(x => x.Active);
HasManyToMany<PersonRole>(x => x.PersonRoles)
.ParentKeyColumn("RoleId")
.ChildKeyColumn("PersonId")
.Cascade.All()
.Table("crm_people_roles_mapping");
//Map(x => x.AccountId);
References(x => x.Account, "AccountId").Column("AccountId");
Table("crm_people");
}
Issue:
When saving a new person with an account id everything saves OK except for the acccount id field.
A person doesn't need to have an account to exist.
What am I doing wrong?
Thanks.
HNibernate doesn't know what to do with your AccountId. On your person object, you've got an Account and an AccountId property. I'll bet if you assigned the Account to the person before you save it, it'd all start working.
Get rid of that AccountId property. You don't need it.