Entity Framework - Single Entity to Multiple Tables - entity-framework-5

I am having some difficulty in mapping single entity to a two different tables in a Entity Framework out of which one is optional to give a quick overview.
I have one main table which is of a core table that lot of our applications in our company uses it, so we really don't want to make any changes to this table.
In our new application we needed a few more columns to support some of the features we are adding.
I have created a single Entity Model that will save information to both these tables, it is working fine when both these tables has the records (related by primary key and foreign key)
But for the historical record this new table will not have a associated record and not able to fetch any entity set.
Below is the code snippet.
public class ModelTable
{
public string PatientID { get; set; }
public string Diagnosis1 { get; set; }
public string Diagnosis2 { get; set; }
public string Diagnosis3 { get; set; }
public string Diagnosis4 { get; set; }
public string Diagnosis5 { get; set; }
public string Diagnosis6 { get; set; }
public string Diagnosis7 { get; set; }
public string Diagnosis8 { get; set; }
}
public class ModelTableMap : EntityTypeConfiguration<ModelTable>
{
public ModelTableMap()
{
//Table1
this.Map(model =>
{
model.Properties(table1 => new
{
table1.Diagnosis1,
table1.Diagnosis2,
table1.Diagnosis3,
table1.Diagnosis4,
table1.Diagnosis5,
table1.Diagnosis6
});
model.ToTable("Table1");
});
//Optional Table
this.Map(model =>
{
model.Properties(table2 => new
{
table2.Diagnosis7,
table2.Diagnosis8,
});
model.ToTable("Table2");
});
this.HasKey(type => type.PatientID);
this.Property(type => type.PatientID).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(type => type.Diagnosis1).HasColumnName("Diag1");
this.Property(type => type.Diagnosis1).HasColumnName("Diag2");
this.Property(type => type.Diagnosis1).HasColumnName("Diag3");
this.Property(type => type.Diagnosis1).HasColumnName("Diag4");
this.Property(type => type.Diagnosis1).HasColumnName("Diag5");
this.Property(type => type.Diagnosis1).HasColumnName("Diag6");
this.Property(type => type.Diagnosis1).HasColumnName("Diag7");
this.Property(type => type.Diagnosis1).HasColumnName("Diag8");
}
}
If I split these tables into a two different POCO classes and specify the relationshipt it is working fine.
But I want to achieve this with Single Entity, since functionally it is a same table.
Please provide any guidance or if I am doing any wrong and please bare with my English is not that good.
Thanks
Sathish

Entity splitting in current EF version requires records in both tables. If you want to use entity splitting you must create empty record for all existing records from the first table. Otherwise you cannot use entity splitting.

Related

Automapper & EF Core: One-to-many relationship exposed by DTO

I effectively have the following entities defined:
public class Order
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Part
{
public int Id { get; set; }
public string Description { get; set; }
public int? OrderId { get; set; }
public Order Order { get; set; }
}
They are configured so that the OrderId in Part is linked to the Order Id:
// Order Model Builder
var orderModelBuilder = modelBuilder.Entity<Order>()
.ToTable("Orders");
orderModelBuilder.HasKey(i => i.Id);
orderModelBuilder.HasMany<Part>()
.WithOne()
.HasForeignKey(i => i.OrderId);
// Part Model Builder
var partModelBuilder = modelBuilder.Entity<Part>()
.ToTable("Parts");
partModelBuilder.HasKey(i => i.Id);
partModelBuilder.HasOne(i => i.Order)
.WithMany()
.HasForeignKey(i => i.OrderId);
Now I would like to map these to a detailed order DTO which includes a collection of parts for an order:
public class PartDto
{
public int Id { get; set; }
public string Description { get; set; }
}
public class OrderDetailsDto
{
public int Id { get; set; }
public string Name { get; set; }
public List<PartDto> Parts { get; set; }
}
Currently, I use Automapper's ProjectTo() to handle queries so I can query what I want and get a list of orders back already mapped to my desired DTO. Now, I want to add Parts to that query so I can get all of the orders back with parts in one query without having to loop through orders and individually fetch the parts for each order returned. I could easily do that if List was part of the Order entity class but adding it at this stage isn't really an option.
CreateMap<Part, PartDto>()
.ForMember(d => d.Id, a => a.MapFrom(s => s.Id))
.ForMember(d => d.Description, a => a.MapFrom(s => s.Description))
;
CreateMap<Order, OrderDetailsDto>()
.ForMember(d => d.Id, a => a.MapFrom(s => s.Id))
.ForMember(d => d.Name, a => a.MapFrom(s => s.Name))
.ForMember(d => d.Parts, a => a.MapFrom(s => ?????))
;
.
..
...
await dbContext.Set<Order>().Where(...).ProjectTo<OrderDetailsDto>(configurationProvider).ToListAsync()
I know I can get shadow variables using EF.Property(object, name) but not sure how to load a restricted collection (dbContext.Set.Where(i => i.OrderId == orderId)). Any suggestions would be greatly appreciated!
--
I'm also open to adding another Entity class if there is a way to make it exist next to the existing entity. So far, I can't find a way to do that without EF Core complaining that it can only have one entity per class (without a discriminator column which would defeat the purpose!).

Saving a collection of records in Orchard

Currently I have a part that has 3 fields (Name, Value1, Value2). I have everything working where I can do a Create/Edit/Delete on the part.
What I want to do now is have a grid with 3 columns (Name, Value1, Value2) and can have multiple rows (up to the user how many there will be). The save won't happen until the user done (save all rows in a single post back).
I haven't figured what is needed so a collection of items will get saved on post back.
Any suggestions on how to do this?
Thanks!
What you could have is to have, in the part, a collection of the records corresponding to (Name, Value1, Value2) by having your dbms create and manage a 1-to-n relationship.
For example, you would have
public class ThisIsYourPart : ContentPart<ThisIsYourPartRecord> {
// You can access the list of your records as
// yourPart.Record.YourRecords
}
public class ThisIsYourPartRecord : ContentPartRecord {
public ThisIsYourPartRecord () {
YourRecords= new List<YourRecordWithValues>();
}
public virtual IList<YourRecordWithValues> YourRecords{ get; set; }
}
public class YourRecordWithValues {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Value1 { get; set; } // use your actual type
public virtual ThisIsYourPartRecord ThisIsYourPartRecord { get; set; }
}
public class YourMigration : DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("YourRecordWithValues ", table => table
.Column<int>("Id", col => col.Identity().PrimaryKey())
.Column<string>("Name", col => col.NotNull().Unlimited())
.Column<string>("Value1", col => col.NotNull().Unlimited())
.Column<int>("ThisIsYourPartRecord_Id"));
SchemaBuilder.CreateTable("ThisIsYourPartRecord", table => table
.ContentPartRecord());
}
}
Code like that should do it.
We used this kind of relations a lot in https://github.com/bleroy/Nwazet.Commerce
*edit:
of course, have all the code in the proper files and folders.

C# Asp.net WebApi how to not populate ID field for the Entity when post in CRUD

I am creating simple webapi with CRUD functionality.
I have an entity say for eg: Product.
I am using FluentNHibernate to map the tables. The Id is generated by sequence.
public ProductMap()
{
Table("PRODUCT");
Id(x => x.Id).GeneratedBy.Sequence("SEQ_REC_SCH_INFO").Column("SCH_ID");
Map(x => x.Name, "Name");
Map(x => x.Category, "Category");
Map(x=>x.Price,"Price");
}
So I dont want the Id parameter of the Product to be populated when i post the data.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
How to make other fields passed to the api controller except Id field?
Thanks
The best way to pass models between systems is ViewModels, with this approach you can ignore some properties in certain cases and include them in other cases, but if you want to ignore this property in all cases you can use JsonIgnore attribute to prevent these properties from serializing.

Fluent Hibernate One-To-One mapping issue

I am not sure how to map below given entities.
Below are the tables.
Employee { ID, Name, Role_ID } (Role_ID is foreign key from Role table)
Role {Role_ID, Name }
Below are the classes:
class Employee
{
public virtual string ID { get; set; }
public virtual string Name { get; set; }
public virtual Role EmpRole { get; set; }
}
class Role
{
public virtual string RoleID { get; set; }
public virtual string Name { get; set; }
}
Below are the Mappings:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Table("Employee");
Id(x => x.ID, "ID");
Map(x => x.Name, "NAME");
//for relationship not sure which mapping to be used???
}
}
public class RoleMap : ClassMap<Role>
{
public RoleMap()
{
Table("Role");
Id(x => x.RoleID, "ROLE_ID");
Map(x => x.RoleID, "ROLE_ID");
Map(x => x.Name, "ROLE_NAME");
//For relationship not sure what to be used????
}
}
Scenario : One Employee will have one role. One Role can be assigned to multiple employee.
Please suggest me how to write the relationship for both entities?
You are facing the most common scenario. The mapping in this case would be many-to-one which in fluent is represented with .References()
public EmployeeMap()
{
Table("Employee");
Id(x => x.ID, "ID");
Map(x => x.Name, "NAME");
References(x => x.EmpRole , "Role_ID");
}
The best overview (I am aware about) is available here:
Mapping-by-Code - ManyToOne by Adam Bar
Suprisingly this post is not about fluent NHibernate but about mapping by code. The second half however, compares with fluent - and provides really comprehensive overivew. Small snippet:
References(x => x.PropertyName, "column_name")
.Class<ClassName>()
.Cascade.SaveUpdate()
.Fetch.Join()
.Update()
.Insert()
.ReadOnly()
.Access.Field()
.Unique()
.OptimisticLock()
.LazyLoad(Laziness.Proxy)
.PropertyRef(x => x.PropertyRef)
.NotFound.Ignore()
.ForeignKey("column_fk")
.Formula("arbitrary SQL expression")
.Index("column_idx")
.Not.Nullable()
.UniqueKey("column_uniq");
In case you would search for NHibernate doc (fluent operates on top of it) you should check the:
5.1.10. many-to-one
If you want Fluent-NHibernate doc:
Fluent mapping
Finally, if you like to see which Employees belong to each Role, you can extend your POCO:
class Role
{
public virtual string RoleID { get; set; }
public virtual string Name { get; set; }
public virtual IList<Employee> Employees { get; set; }
}
And map it as a <bag>.
HasMany(x => x.Employees)
.KeyColumn("Role_ID")
.Inverse()
.BatchSize(25)
See:
6.1. Persistent Collections (NHibernate doc for one-to-many)
Mapping-by-Code - Set and Bag - again by Adam Bar, second half about fluent

Automapper newbie question regarding list property

As a new fan of AutoMapper, how would I use it to do the following:
Given the following classes, I want to create FlattenedGroup from Group where the list of item string maps to the title property of Item.
public class Group
{
public string Category { get; set; }
public IEnumerable<Item> Items { get; set; }
}
public class Item
{
public int ID { get; set; }
public string Title { get; set; }
}
public class FlattenedGroup
{
public string Category { get; set; }
public IEnumerable<string> Items { get; set; }
}
Thanks
Joseph
The other thing you can do is create a converter from Item -> string:
Mapper.CreateMap<Item, string>().ConvertUsing(item => item.Title);
Now you don't need to do anything special in your Group -> FlattenedGroup map:
Mapper.CreateMap<Group, FlattenedGroup>();
That's all you'd need there.
Give this a try, you can probably use Linq and a lambda expression to map the list of strings in FlattenedGroup with the titles in Group.
Mapper.CreateMap<Group, FlattenedGroup>()
.ForMember(f => f.Category, opt => opt.MapFrom(g => g.Category))
.ForMember(f => f.Items, opt => opt.MapFrom(g => g.Items.Select(d => d.Title).ToList()));
Make sure you add System.Linq to your using statements

Resources