how to get data in Custom property based on Complex type property in EntityFramework Code first approach - ef-code-first

Hi all I am new to Code first approach and complex type in Entity framework (version 5). I am working on some functionality where i have to fetch data based on property in complex type, I tried many ways but could not succeed. below are the details on my implementation.
Database MainTable1 =>
int IDField1_Maintbl [Primarykey], int Filed2, ..., varchar Fieldn
I have another detail table
Database DetailTable1 =>
int IDField1 [PrimaryKey],int IDField1_Maintbl[ForeignKey], varchar Field2, varchar Field3, int A_IDField4, varchar A_Field5, varchar A_Field6, ..., varchar Field10,
the last table on which I am working is as below
Table2 =>
int A_IDField4 [PrimaryKey], varchar Field2_tbl2, bool? Field3_tbl2,
here I have relation between Table2 and DetailTable1 as 1:M in database based on Table2.A_IDField4 and DetailTable1.A_IDField4 fields.
Respective Entities in C# are as below:
public classEntityForMainTable1
{
public int IDField1_Maintbl {get;set;}
public int Filed2 {get;set;}
...
public varchar Fieldn {get;set;}
public IList<EntityForDetailTable1> table1Data{get;set;}
}
public class EntityForDetailTable1
{
public int IDField1 {get;set;}
public string Field2 {get;set;}
public string Field3 {get;set;}
public string AField7 {get;set;}
...
public string Field10 {get;set;}
public Table1ComplexType tble1ct {get;set;}
}
public class EntityTable2
{
public int A_IDField4 {get;set;}
public string Field2_tbl2 {get;set;}
public bool? Field3_tbl2 {get;set;}
}
public class DetailTable1ComplexType //Complex Type
{
public int A_IDField4 {get;set;}
public string A_Field5 {get;set;}
public string A_Field6 {get;set;}
}
OnModelCreating method is as below:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<classEntityForMainTable1>().ToTable("MainTable1", "Custom");
modelBuilder.Entity<EntityForDetailTable1>().ToTable("DetailTable1", "Custom");
modelBuilder.Entity<EntityTable2>().ToTable("Table2", "Custom");
RegDetailTable1ComplexType.Register(modelBuilder); //RegDetailTable1ComplexType is a static class that register the complex type.
}
What my requirement is; I have to add custom property in EntityForDetailTable1 as :
public bool? Field3_tbl2 {get;set;}
This property should return value of Field3_tbl2 from Table Table2 depend on value of A_IDField4 from entity DetailTable1ComplexType and EntityTable2
Any help would appriciated.

Related

How to seed an enum in Entity Framework Core 2.1

I am new to EF Core, and am trying to seed an enum.
According to Data Seeding, this feature is new to EF Core 2.1.
I reviewed several solutions including this SO solution by Blake Mumford, but this doesn't work for me since an enum is not a reference type.
My goal (with the help from migrations) is to have the Category enum to be populated in a new SQL table called Category, and have my Payment table contain a column that references the Category table as a foreign key.
Any help would be greatly appreciated. Thanks.
public partial class Payment
{
public int PaymentId { get; set; }
public DateTime PostedDate { get; set; }
public string Vendor { get; set; }
public decimal Amount { get; set; }
public virtual Category Category { get; set; }
}
public enum Category
{
Restaurants,
Groceries,
[Display(Name = "Home Goods")]
HomeGoods,
Entertainment
}
public partial class MyDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Error: The type Category must be a reference type in order to use it as parameter TEntity in the
// genric type or method ModelBuilder.Entity<TEntity>()
modelBuilder.Entity<Category>().HasData(Category.Restaurants,
Category.Groceries,
Category.HomeGoods,
Category.Entertainment);
}
}
This is what I did hopefully it will work with your environment.
Environment
Project Framework
.NetCore 3.0
Nugets:
EFCore 3.1.2
EFCore.Design 3.1.2
EFCore.Tools 3.1.2
EFCore.Relational 3.1.2
EFCore.SqlServer 3.1.2
Implementation
Add OnModelCreating
public partial class MyDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Error: The type Category must be a reference type in order to use it as parameter TEntity in the
// genric type or method ModelBuilder.Entity<TEntity>()
modelBuilder.Entity<UserRole>().HasData(EnumFunctions.GetModelsFromEnum<UserRole, UserRoleEnum>());
}
}
Create a Generic Enum Function
public static class EnumFunctions
{
public static IEnumerable<TModel> GetModelsFromEnum<TModel, TEnum>() where TModel : IEnumModel<TModel, TEnum>, new()
{
var enums = new List<TModel>();
foreach (var enumVar in (TEnum[])Enum.GetValues(typeof(TEnum)))
{
enums.Add(new TModel
{
Id = enumVar,
Name = enumVar.ToString()
});
}
return enums;
}
}
Create an Interface
public interface IEnumModel<TModel, TModelIdType>
{
TModelIdType Id { get; set; }
string Name { get; set; }
}
Apply the interface to the model
[Table("UserRoles")]
public class UserRole : IEnumModel<UserRole, UserRoleEnum>
{
[Key]
public UserRoleEnum Id { get; set; }
public string Name { get; set; }
}
Add your migration
PM> add-migration SeedUserRoleTable
You should see the migration added
Update the database with the seeded info
PM> update-database
Under my Entities folder I have added Enumerations folder, I have this:
public class UserStatus : Enumeration
{
public static readonly UserStatus New = new UserStatus(1, "New");
public static readonly UserStatus UnderReview = new UserStatus(2, "UnderReview");
public static readonly UserStatus Customer = new UserStatus(3, "Customer");
public static readonly UserStatus Approved = new UserStatus(4, "Approved");
public static readonly UserStatus Declined = new UserStatus(5, "Declined");
public UserStatus(int id, string name)
: base(id, name)
{
}
}
In my DataContext.cs I just use this to seed data:
modelBuilder.Entity<UserStatus>().HasData(Enumeration.GetAll<UserStatus>());
UserStatus is not declared as DbSet in DataContext.cs
.NET Core 3.1
You cannot seed values for an enum type to the database because enums are not entity types and thus do not go into the database in the first place. In other words, there will be no Categories table, so it makes no sense to seed values into that non-existent table.
If you want to actually have your categories be persisted in your database, then you need to create a class like:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}

Asp.net mvc4 how to join entities by using linq

I have a problem with joining two entities by linq language.
I have model Category:
public class Category : DbContext
{
[Key, Column(Order = 0),DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CategoryId { get; set; }
Key, Column(Order = 1)]
public int ShopId { get; set; }
public string Name {get;set;}
public virtual ICollection<Parameter> Parameter { get; set; }
}
and model Parametr
public class Parameter : DbContext
{
[Key, Column(Order = 0),DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ParamId { get; set;}
[Key, Column(Order = 1)]
public int ShopId { get; set;}
public string Name {get; set;}
public string Value {get;set;}
}
The relation is one to many, so one Category coud have 0...n Parameters.
UPDATE:
Sure, the relationship is many to many. This is the reason, why Parameter has no CategoryId attribute in the model.
I'm using code first and migration tool for updataing database;
In database MSSQL Express are 3tables. Category, CategoryParameters and Parameters.
Table CategoryParameter was created automaticaly and I have no Model for this table.
Creating new Category with multiple Parameters working fine. All 3tables contains valid data.
So my problem now:
I'm trying to load all parameters for one Category. The command looks like:
var parameters = from c in db.Categories
join p in db.Parameters
on new { ??? , c.ShopId } equals new { ??? , p.ShopId }
where c.ShopId == userProfile.ShopId && c.CategoryId == id
select new { ParamId = p.ParamId, Name = p.Name };
So my problem is, how to hell join these tables, if there is no usable atribute in the classes.
Many thanks for any help!
You don't need JOIN: use navigation property instead:
Find the category entity.
Use Parameter property of the category entity.
var parameters = db.Categories.First(x => x.CategoryId == 10).Parameter.ToList();

Getting "Cannot insert the value NULL into column" when trying to save with .Add() method using DbContext . Please check my POCO's and save method

Used code first and everything appears to work apart from the below which also worked before when I used ObjectContext and called context.PCBuilds.AddObject(pcBuild) but after switching to DbContext it's giving me the error.
EFDbContext context = new EFDbContext();
public ActionResult Index()
{
PCBuild pcBuild = new PCBuild();
pcBuild.BuildID = 34245;
pcBuild.BuildName = "Test99";
pcBuild.MarkUp = 25;
pcBuild.BDetails = new List<BDetail>();
context.PCBuilds.Add(pcBuild);
//repository.PCBuilds.Attach(pcBuild);
context.SaveChanges();
return View();
}
Giving me the: Cannot insert the value NULL into column 'BuildID', table 'C:\USERS\ADMIN\DOCUMENTS\VISUAL STUDIO 2010\PROJECTS\NEOCART\NEOCART.WEBUI\APP_DATA\NEODBX.MDF.dbo.PCBuilds'; column does not allow nulls. INSERT fails. Where as BuildID was clearly set before the SaveChanges is called. Appears that calling the .Add(pcBuild) doesn't add the populated object for some reason and when savechanges is called it attempts to insert an empty PCBuild ?
Here are the POCO's
public class PCBuild
{
[Key]
public int BuildID { get; set; }
public string BuildName { get; set; }
public string Socket { get; set; }
public decimal? MarkUp {get; set;}
[InverseProperty("PCBuild")]
public virtual ICollection<BDetail> BDetails { get; set; }
}
public class BDetail
{
[Key]
public int LineID { get; set; }
[ForeignKey("PCBuild")]
public int BuildID { get; set; }
[ForeignKey("Product")]
public int ProductID { get; set; }
public bool? IsSelected { get; set; }
[InverseProperty("BDetails")]
public virtual PCBuild PCBuild { get; set; }
[InverseProperty("BDetails")]
public virtual Product Product { get; set; }
}
Use StoreGeneratedAttribute on the PCBuild.BuildID property. It is not only a key but IDENTITY field.
UPDATE
Actually, it should be [DatabaseGenerated(DatabaseGenerationOption.Identity)] annotation. The article linked above describes early CTP version.
UPDATE 2
Wait, the key is being generated by the app, it is not an identity column in database? Change annotation to [DatabaseGenerated(DatabaseGenerationOption.None)], re-create the context and rebuild the application.
I'm not really familiar with the Code First approach, but could it be that when you specify the BuildID as being a [Key] field, it is setting it as an auto identity field in the database?
As such it may be blocking your attempt to write to it.
Try removing the [Key] identifier, then recreate the database. Can you then save the object ok?

Define association using database column and not entity type property

public class Order {
public int OrderID {get; set;}
public DateTime DateOrdered { get; set; }
public ICollection<OrderLine> OrderLines { get; set; }
}
public class OrderLine{
public int OrderLineID { get; set; }
public int OrderID {get; set; } // I want to remove this
public string ItemName { get; set;}
public Int Qty { get; set; }
}
How would I map these using the Fluent API? I am using these in a repository pattern where Order will be the root of the aggregate. As such I do not want OrderLine to have a reference to Order or have an OrderID. Since the OrderLine only makes any sense because its a child of Order.
Currently I am using this:
HasMany<OrderLine>(x => x.OrderLines).WithRequired().HasForeignKey(x => x.OrderID);
I am using an existing database structure here and ideally I would map this using the database column name. So somehow tell it to use tblOrderLine.colOrderId rather then OrderLine.OrderID.
You can use the Map() method to map your FK
HasMany<OrderLine>(x => x.OrderLines)
.WithRequired()
.Map(m => m.MapKey("colOrderId"));

How do you actually perform relationships in Entity Framework 4 Code-First CTP 5?

I would like to have a short example on how do you actually perform relationships in Entity Framework 4 Code-First CTP 5 ?
Would love an example for these kind of relations :
* one-to-many
* many-to-many
Thanks a lots!
One to One
public class One
{
public int Id {get;set;}
public virtual Two RelationTwo {get;set;}
}
public class Two
{
public int Id {get;set;}
public virtual One RelationOne {get;set;}
}
Things to note, it has to be virtual
One to Many
public class One
{
public int Id {get;set;}
public virtual ICollection<Two> RelationTwo {get;set;}
}
public class Two
{
public int Id {get;set;}
public virtual One RelationOne {get;set;}
}
Many to Many
public class One
{
public int Id {get;set;}
public virtual ICollection<Two> RelationTwo {get;set;}
}
public class Two
{
public int Id {get;set;}
public virtual ICollection<One> RelationOne {get;set;}
}
note that it needs to be ICollection
Following links maybe helpful, click and click
Hope this helps.
EDIT
Updated to include one to many.
EDIT #2
Updated to include a potential for doing the Invoice <-> Product scenario which was requested by comment.
note: this is untested, but should put you in the right direction
public class Invoice
{
public int Id {get;set;}
//.. etc. other details on invoice, linking to shipping address etc.
public virtual ICollection<InvoiceProduct> Items {get;set;}
}
public class InvoiceProduct
{
public int Id {get;set;}
public int Quantity {get;set;}
public decimal Price {get;set;} // possibly calculated
//.. other details such as discounts maybe
public virtual Product Product {get;set;}
public virtual Invoice Order {get;set;} // maybe but not required
}
public class Product
{
public int Id {get;set;}
//.. other details about product
}
Using this you could then iterate through all the items on the invoice and then foreach be able to show the invoice details about each item as well as a description from the product itself.

Resources