Entity Framework doesn't generate all tables from database - c#

This is my diagram in my database:
but when I use Entity Framework it was like that:
It hasn't table name ListSuiteQuestion but It has 2 new property in class Question and Suite:
enter image description here

Table ListSuiteQuestion is automatically created by sql because in sql we don't have something called many to many relationship (m:n) and sql creates another table to implement m:n relationship with keys containing the primary key of two relationship tables is also the name of the combination of the names of the two relation tables.
Within your entity framework by accessing each table through another table you have access to that table so there is no need to define it by entity framework. However, if you intend to customize or add a field to a third table you can manually build it into the code and then display it entity framework, though you don't need to.
if you want create it manually in code do like this :
public class Suite
{
//another property
public int IdSuite { get; set; }
public virtual ICollection<SuitQuestions> Questions { get; set; }
}
public class Question
{
//another property
public int IdQuestion { get; set; }
public virtual ICollection<SuitQuestions> Suites { get; set; }
}
public class SuiteQuestions
{
public Suite Suite { get; set; }
public int IdSuite { get; set; }
public Question Question { get; set; }
public int IdQuestion { get; set; }
//add custome property if you need
}
and config it.

It's correct. A question has a list of suites and a suite has a list of questions.
If you do:
var suite = context.Suites.Find(5);
var question = context.Questions.Find(30);
suite.Questions.Add(question);
// And update this suite object here;
You will see a new record in ListSuiteQuestion Tables with IdSuite = 5 and IdQuestion = 30. The class ListSuiteQuestion doesn't need to be created.
However, if you really want to create the class you have to add Id to the Table ListSuiteQuestion as primary key.

Related

C# LINQ Query Hanging

I'm working to create a c# application, and in a portion of the application; I'm looking to bring in a .csv to a data table; and then basically loop through each row and query a database to see if the data exists.
I'm testing a LINQ query; but I can't seem to get it to run and display anything. I have the following code setup to run below:
I have the database added and the connection tests succesfully; I have the classes setup. I've been following some courses on pluralsight to test; and I'm not sure what exactly I am doing wrong or missing.
Also as a note; the table name is actually ERP.PartTran, and not PartTran, but I wasn't succesful in setting that up for the db context; could that be why?
EDIT: Code added; images removed
public class EpiDB : DbContext
{
public DbSet<Tran> PartTran { get; set; }
}
public class Tran
{
public int TranNum { get; set; }
public string TranReference { get; set; }
public string PartNum { get; set; }
}
private static void QueryPartTran()
{
var db = new EpiDB();
int tranref = 4650374; //lookup number
var query = from Tran in db.PartTran
where Tran.TranNum == tranref
orderby Tran.TranNum
select Tran;
foreach (var Tran in query)
{
Debug.Print(Tran.PartNum);
}
}
If you have an existing database schema, the first thing to avoid soft exceptions is to disable schema creation/migration in EF. By default when EF connects to a database and goes to resolve the schema, if it comes across a table that it cannot resolve, it will create it. The clue I see that might be happening in this case is when you say the table is called [ERP].PartTran. I suspect you may find that your database has a new empty table called [dbo].Tran. (assuming SQL Server)
To disable schema creation:
In your Db Context constructor
public EpiDB()
{
Database.SetInitializer<EpiDB>(null);
}
This may go a long ways to identifying any bad schema assumptions that EF is making by convention. Jim's answer would be along the lines of where I would believe your problem will lie.
Entities should map relatively closely, if not identically to your table. Renaming an entity or properties to differ from the table to clarify it in code is fine, but you need to be sure that when you do this, you give EF enough information about your schema so that it can resolve the table correctly. If your table is named "PartTran" and your DbSet instance is named "PartTran", why would you want to name the entity "Tran" rather than "PartTran"?
If your application schema is "ERP" then you can avoid needing to specify the schema name on each entity by adding the following to your DbContext.OnModelCreating():
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("ERP");
// ...
}
Otherwise, if you are using multiple schemas then you will need to explicitly map the schema to use with a [Table] attribute or ToTable("{tableName}", "{SchemaName}") in EntityTypeConfig / modelBuilder config.
Next, ensure that your entity fields match the appropriate fields in the table. You don't need to map every field if you don't need them, but at a minimum you do need to map the Primary Key. On a guess from the PartTran entity, I'm guessing you're either missing something like a PartTranId column, or the PK is a composite key using the PartNum and TranNum columns. If you have a PartTranId or similar PK, add it to the entity along with a [Key] attribute. If the PK is a composite:
public class PartTran
{
[Key, Column(Order = 1)]
public int TranNum { get; set; }
public string TranReference { get; set; }
[Key, Column(Order = 2)]
public string PartNum { get; set; }
}
This should give you a few ideas to check out against your code base... To go further it would help to amend your question to include the related tables and any entities you have tried creating so far. Something like "PartTran" looks like a joining table for a many-to-many relationship between a "Part" table and a "Tran"(saction?) table. If that is the case there are a number of options how you can efficiently wire this up in EF to get the data out the way you want.
Try this:
public class EpiDB : DbContext
{
public DbSet<Tran> PartTran { get; set; }
}
[Table("PartTran", Schema = "ERP")]
public class Tran
{
public int TranNum { get; set; }
public string TranReference { get; set; }
public string PartNum { get; set; }
}
And maybe even:
public class EpiDB : DbContext
{
public DbSet<Tran> PartTran { get; set; }
}
[Table("PartTran", Schema = "ERP")]
public class Tran
{
[Key] // Is this your primary key field?
public int TranNum { get; set; }
public string TranReference { get; set; }
public string PartNum { get; set; }
}

ASP.NET Core 2: What could be the code behind a "many-to-one" relationship in this case?

I'm preparing a project's data structure (code-first) in an ASP .NET Core 2 application, with the help of Entity Framework. This specific relationship I have no experience with: the user has to be able to choose diseases with checkboxes, and we have similar choices: cancer type, dietary, etc..
I have more than two tables like the ones on the picture, which will be referred from the UserKitProperties table. This table should work like a connector table, connects the user entity with other entities.
userid1 | cancertypeid1
userid2 | dietaryid1
userid1 | cancertypeid2
userid3 | dietaryid1
How should this be specified in the code, to support this relationship? I was thinking on doing a base class and maybe refer to that id. And this is the connector class..
public class PatientProperties : EntityModel
{
[Key]
public long ID { get; set; }
public long PatientID { get; set; }
[ForeignKey("PatientID")]
public Patient Patients { get; set; }
// this should be used for cancer type, dietary, etc..
public long PropertyID { get; set; }
/* Instead of using two classes' ids, maybe call the base class' id
[ForeignKey("PropertyID")]
public CancerType CancerTypes { get; set; }
[ForeignKey("PropertyID")]
public Dietary Dietaries { get; set; } */
}
Thank you in advance for your suggestions! :)
The following should work:
public class Property
{
public long PropertyId { get; set; }
}
public class CancerType : Property
{
// Your code
}
public class Dietary : Property
{
// Your code
}
public class PatientProperties : EntityModel
{
[Key]
public long ID { get; set; }
public long PatientID { get; set; }
[ForeignKey("PatientID")]
public Patient Patients { get; set; }
public long PropertyID { get; set; }
[ForeignKey("PropertyID")]
public Property Property { get; set; }
}
But as this MS doc mentions, setting up such inheritence will use a special Discriminator
column in the base class table, to represent what specific type is stored in a row.
I personally would resort to having nullable fields instead in order to not add more complexity. This doesn't enforce, however, that PatientProperties only has one property, which is a considerable minus:
public class PatientProperties : EntityModel
{
[Key]
public long ID { get; set; }
public long PatientID { get; set; }
[ForeignKey("PatientID")]
public Patient Patients { get; set; }
public long? CancerTypeID { get; set; }
[ForeignKey("CancerTypeID")]
public CancerType CancerType { get; set; }
public long? DietaryID { get; set; }
[ForeignKey("DietaryID")]
public Dietary Dietary { get; set; }
}
Instead of thinking about the database layout first, you should think about how you would represent this relationship in code. After all, you are doing a code-first approach.
There are basically two choices you could choose: Either the patient has multiple properties, one for each property type, or there is just a single collection for all properties:
public class Patient
{
// …
// option 1
public CancerType CancerType { get; set; }
public Dietary Dietary { get; set; }
public OtherProperty OtherProperty { get; set; }
// option 2
public IList<PatientProperty> Properties { get; set; }
}
Both of these options have their advantages and disadvantages. While option 1 is very explicit and enforces a single value for every type, it also requires you to have a (class) property for every (patient) property. So if you extend your model later, you will have to adjust your patient model.
Option 2 has the benefit that it can just collect everything. So you can just add properties to your patient without having to modify the model later if you introduce new properties. In addition, it would also directly support multiple selections for a single kind. On the downside, it does not verify anything on its own, so you need business logic to actually enforce your rules.
Moving onto the database, for option 2 you obviously need a link table since that is a many-to-many relationship now. Since you only have a link to the base type PatientProperty but you actually want to talk about the concrete type, you will need some kind of discriminator. Discriminators are basically just a notation to additionally store the kind of object in the database.
When storing data with inheritance, what is commonly done is “table-per-hierarchy”. That means that all types within the hierarchy of the PatientProperty base type will share the same table. A discriminator column is used to specify the type, and additional properties that some property types may have are implemented with nullable columns. This setup works out of the box with Entity Framework and is described in this chapter in the documentation.
The other approach, “table-per-type” is not supported in EF Core, so if you wanted to follow that, you would have to implement it yourself. But in your case, where the property types are mostly very similar, I would actually argue against that and actually keep them in the same table.
For option 1, as long as you only have a single property of each kind assigned to the patient, things are a bit simpler. Since you don’t have many-to-many there, you don’t actually need a link table. You just need to store the id for each linked property type in the patient model, as shown in the above UML. Doing that, you can also keep the property types as separate types that do not share a single table in the database.

NHibernate tries to create indexes for a view

I'm writing a C# application that uses NHibernate to access the database. One of my data sources is a view (not a table) named content_profile. I have created the following sample class using NHibernate Attributes:
[Class(Table = "content_profile")]
public class ContentProfile
{
[Id(0, TypeType = typeof(int), Name = #"Id"), Generator(2, Class = #"identity"), Column(1, Name = #"Id")]
public virtual int Id { get; set; }
[NotEmpty]
[MinLength(1)]
public virtual string Name { get; set; }
[Property]
public virtual DateTime? CreationDate { get; set; }
[ManyToOne(Lazy = Laziness.False, Column = #"author_id")]
public virtual User Owner { get; set; }
}
When trying to update schema I get the following error:
NHibernate.Tool.hbm2ddl.SchemaUpdate [(null)] - Unsuccessful: alter table public.content_profile add constraint FK280FFEFD6A68A1F9 foreign key (author_id) references public.users
Npgsql.NpgsqlException:
"content_profile" - is not a table
How do I tell NHibernate that it is indeed a view, not a table, and indexes must not be created on schema update?
You can specify that there should not be done any action on the schema of a certain class map by adding SchemaAction.None, never really used attributes because it lacks features but it should have something like [Class(SchemaAction="None")]

Entity Framework Creates New / Duplicate Entries for Associated Objects

I am trying to use Code First to create an SQL CE 4 database. When running the sample code below, Entity Framework is inserting new records for product each time, even though the data is exactly the same. What do I need to do to make Entity Framework not create duplicate associated products? The values in the ForeignID1 and the Product object are values that already exist in the database, but Entity Framework is wiping the ID I give it and adding a new ID.
namespace MyApp.Model
{
public class MyThing
{
public int ID { get; set; }
[ForeignKey("Product")]
public int ForeignID1{ get; set; }
public virtual Product Product { get; set; }
}
}
// Data.DataManager.cs
public class DataManager : DbContext
{
public DbSet<Model.MyThing> Things{ get; set; }
public DbSet<Model.Product> Products { get; set; }
}
These are the values it has entered. There should only be one value in the table that is referenced by multiple MyThings's
In order to avoid the duplication you must attach the related entity to the context:
context.Products.Attach(myThing.Product);
context.Things.Add(myThing);
Or...
myThing.Product = null;
context.Things.Add(myThing);
...will work as well if you have set myThing.ForeignID1 to an existing Product ID.

How should I access a computed column in Entity Framework Code First?

I am using Entity Framework Code First in my ASP.NET MVC application. One of my classes has several columns that are added together. I am storing these columns as computed columns in the tables by running an alter table script in the database initializer. Let's say the class looks like:
public class Bond
{
public decimal ParAmountOfIssuance { get; set; }
public decimal AccruedInterest { get; set; }
public decimal Premium { get; set; }
public decimal OriginalIssueDiscount { get; set; }
}
The alter script is something like:
alter table Bonds
add TotalSources as (ParAmountOfIssuance + AccruedInterest + Premium - OriginalIssueDiscount)
I want the Total Sources column to be available for viewing in the web app. What's the best way to accomplish this? The [DatabaseGenerated(DatabaseGeneratedOption.Computed)] attribute doesn't work because EF Code First creates the table from the class before the alter script is ran.
Any suggestions are welcome.
I have a somewhat of an workaround.
You can only use calculated field on a existing database.
If you add your property to CF object as:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public decimal TotalSources { get; set; }
and if you add a line in your script that will delete information about generation of that database:
DELETE FROM [dbo].[EdmMetadata]
CF will assume it is existing database and it will work, I have just tried.
UPDATE I forgot, if you add property to your Bond entity like this, then in your script you need to alter it to make it calculated, not add it :)
You can even manually "synchronize" database and model - at point where you have everything working without this field, add it in model as computed, and in table as calculated. When you delete hash from edm metadata table CF will work without trying to regenerate model with database.
This is definitely not supported - defining Computed option on custom property will throw exception. Code first = logic in code. If you need custom computed properties use database first. The only database logic supported by code first is identity column and timestamp.
The problem is that you need the column to be marked as computed but creating database will not allow that. If the column is not marked as computed it will be updatable = EF will generate update statements trying to update this column which will fail in the database.
I'm doing computed columns in CF (WinForms) like that (I don't know if it's the best):
This is one Entity:
public class Result
{
public int ResultId { get; set; }
public int StudentId { get; set; }
public Student Student { get; set; }
public float Arabic { get; set; }
public float English { get; set; }
public float Math { get; set; }
public float Science { get; set; }
public float Total { get; set; }
}
This is Form2:
private void Form2_Load(object sender, EventArgs e)
{
Model1 model = new Model1();//Model1 : DbContext
model.Database.CreateIfNotExists();
model.Database.ExecuteSqlCommand("alter table Results drop column Total; alter table Results add Total AS (Arabic + English + Math + Science)");
var r1 = (from s in model.Students
join r in model.Results
on s.StudentId equals r.StudentId
select new { s.StudentName, r.Arabic, r.English, r.Science, r.Math, r.Total }).ToList();
dataGridView1.DataSource = r1;
}

Categories

Resources