Entity Framework navigational property between different column names - c#

I have two EF models -
public class What
{
[Key]
public int primary_key_What { get; set; }
public int another_column_What { get; set; }
public virtual ICollection<Why> Whys { get; set; }
}
And
public class Why
{
[Key]
public int primary_key_Why { get; set; }
public int some_column_Why { get; set; }
public virtual What What { get; set; }
}
The problem is, I have to use another_column_What and some_column_Why for navigating between the two. As you can see none of them are keys or declared unique in the database, also their names are different.
I've tried all the ways I could imagine of and found on search, but none of them works. How and in which model mapping do I use to say, navigate between What and Why using another_column_What and some_column_Why columns.
So whenever a query is generated by EF, it will compare another_column_What with some_column_Why?
Very unfortunately, changing the database architecture (or even column names) is not an option here.
Can anyone please help me with it?

This should work:
Db schema:
What model:
[Table("what")]
public class what
{
[Key]
[Column("primary_key_what")]
public int primary_key_what { get; set; }
[Column("another_column_what")]
public int another_column_what { get; set; }
public virtual ICollection<why> whys { get; set; }
}
Why model:
[Table("why")]
public class why
{
[Key]
[Column("primary_key_why")]
public int primary_key_why { get; set; }
[ForeignKey("what")]
[Column("some_column_why")]
public int some_column_why { get; set; }
public virtual what what { get; set; }
}
Context:
public class Context : DbContext
{
public virtual DbSet<what> what { get; set; }
public virtual DbSet<why> why { get; set; }
public Context() : base("name=SqlConnection")
{
}
}
Main:
static void Main(string[] args)
{
using (var context = new Context())
{
var results = from w in context.what
select w;
foreach (var what in results)
{
Console.WriteLine("what.primary_key_what = {0}", what.primary_key_what);
Console.WriteLine("what.another_column_what = {0}", what.another_column_what);
Console.WriteLine("what has {0} whys", what.whys.Count);
foreach (var why in what.whys)
{
Console.WriteLine("Why.primary_key_why = {0}", why.primary_key_why);
Console.WriteLine("Why.some_column_why = {0}", why.some_column_why);
}
}
}
}
What data:
Why data:
Output:

Related

Is it possible to add Rootobject with subclasses in one go to Entity Framwork?

I'm trying to Deserialize data into an object, and then add that object to a sqlite database with Entity Framework.
The first part is working fine.
But if try to add the object to the database I get this error:
System.InvalidOperationException: 'The instance of entity type 'Client' cannot be
tracked because another instance with the same key value for {'id'} is already being
tracked. When attaching existing entities, ensure that only one entity instance with a
given key value is attached. Consider using
'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key
values.'
Is it not possible to add the Rootobject with all the subclasses in one go?
Here is my code, I did not include all the sub classes.
All classes has an Id field:
HttpClient client = new HttpClient();
//Add headers etc. ...
var result = await client.GetAsync(url);
string? content = await result.Content.ReadAsStringAsync();
var TimeEntries = JsonConvert.DeserializeObject<Rootobject>(content);
using (var database = new DataContext())
{
database.Add(TimeEntries);
database.SaveChanges();
}
public class DataContext : DbContext
{
public DbSet<Rootobject>? RootObjects { get; set; }
public DbSet<Link>? Links { get; set; }
public DbSet<Time_Entry>? Time_Entries { get; set; }
public DbSet<User>? Users { get; set; }
public DbSet<Client>? Clients { get; set; }
public DbSet<Project>? Projects { get; set; }
public DbSet<Task>? Tasks { get; set; }
public DbSet<User_Assignment>? User_Assignments { get; set; }
public DbSet<Task_Assignment>? Task_Assignments { get; set; }
public DbSet<External_Reference>? External_References { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder dbContextOptionsBuilder)
{
dbContextOptionsBuilder.UseSqlite("Data Source=data.db");
}
}
public class Rootobject
{
public int Id { get; set; }
public ICollection<Time_Entry>? Time_entries { get; set; }
public int Per_page { get; set; }
public int Total_pages { get; set; }
public int Total_entries { get; set; }
public int ?Next_page { get; set; }
public int ?Previous_page { get; set; }
public int Page { get; set; }
public Link? Links { get; set; }
}

Entity Framework 6 - Database schema is not updating

I am learning EF
I wanted to play with the different types of inheritance using code first.
I initially started off with a few classes and ran my application. I saw the database get created with all my classes represented as tables.
However, when I add new classes or fields and run the application again, I do not see the changes in my database schema.
I have used the "DropCreateDatabaseAlways", so I don't understand why my database is not being updated with the proper schema as I add fields and classes. Can someone explain what I am doing wrong?
Initial Code:
namespace Domain
{
public class Good
{
public int Id { get; set; }
public string Name { get; set; }
public double BaseValue { get; set; }
}
public class Manufacturer {
public int Id {get; set;}
public ICollection<ManufacturingCapability> ManufacturingCapabilities { get; set; }
}
public class ManufacturingCapability {
public int Id { get; set; }
public ICollection<ManufacturingInput> Inputs { get; set; }
public ICollection<ManufacturingOutput> Outputs { get; set; }
public TimeSpan CycleTime { get; set; }
}
public class ManufacturingInput {
public int Id { get; set; }
public Good Good { get; set; }
public uint Quantity { get; set; }
}
public class ManufacturingOutput {
public int Id { get; set; }
public Good Good { get; set; }
public uint Quantity { get; set; }
}
public class ManufacturingDbContext :DbContext {
public DbSet<Good> Goods { get; set; }
public DbSet<Manufacturer> Manufacturers { get; set; }
public ManufacturingDbContext() : base("name=EFLearnConnectionString") {
Database.SetInitializer<ManufacturingDbContext>(new DropCreateDatabaseAlways<ManufacturingDbContext>());
}
}
}
namespace EFLearning {
class Program {
static void Main(string[] args) {
using (var manufacturingDbContext = new ManufacturingDbContext()) {
var good = new Good() { Name = "Water" };
manufacturingDbContext.Goods.Add(good);
manufacturingDbContext.SaveChanges();
}
}
}
}
Database Tables in Management Studio after running:
Added code:
public class Station : Manufacturer {
public string Name { get; set; }
public Vector3 Location { get; set; }
}
and I added this to context:
public DbSet<Station> Stations { get; set; }
Database Tables in Management Studio after running:
Your strategy for domain design to station and manufactor entity is Table per Hierarchy.so stations properties are now in manufactors table.
go to this link for more information.
if you you want Station entity have a seperate table must use of Table per Type
go to this link for Table per Type

How to get "child" rows directly in any to many relationship EF6

I have EF6 model with many to many relationship like this (I simplified my model to make it more clear):
public class Card
{
public int CardId { get; set; }
public string CardTitle { get; set; }
public virtual ICollection<CardLayout> CardLayouts { get; set; }
}
public class Layout
{
public int LayoutId { get; set; }
public string LayoutTitle { get; set; }
public virtual ICollection<CardLayout> CardLayouts { get; set; }
}
public class CardLayout // relationship table
{
public int CardLayoutId { get; set; }
public int CardId { get; set; }
public int LayoutId { get; set; }
public int CardLocation { get; set; }
public virtual Card Card { get; set; }
public virtual Layout Layout { get; set; }
}
This is how I use it for now:
int exampleId = 23;
using (MyContext ctx = new MyContext())
{
Card c = ctx.Cards.Find(23);
foreach (CardLayout cardLayout in c.CardLayouts)
{
Layout layout = cardLayout.Layout;
DoSomethingWithLayout(layout);
}
}
I need Layout collection directly inside my Card object. I don't want to pass thru relationship table. I want to use it like this:
int exampleId = 23;
using (MyContext ctx = new MyContext())
{
Card c = ctx.Cards.Find(23);
foreach (Layout layout in c.Layouts)
{
DoSomethingWithLayout(layout);
}
}
I have tried something like this:
public class Card
{
public int CardId { get; set; }
public string CardTitle { get; set; }
public virtual ICollection<CardLayout> CardLayouts { get; set; }
public virtual ICollection<Layout> Layouts { get; set; }
}
But Layouts collection is always empty.
My question is: how can I access Layouts collection directly from Card object? I want to keep Card.CardLayouts collection too, because my CardLayouts table contains fields (like CardLocation in my simplified example)
Ps. Can someone improve my question title? My english is not good enough to write it better. Thanks in advance.
While I think that #Biscuits' comment is correct. If you don't want to go that route for whatever reason, you should just be able to create another property with a getter only.
public class Card
{
public int CardId { get; set; }
public string CardTitle { get; set; }
public virtual ICollection<CardLayout> CardLayouts { get; set; }
[NotMapped]
public IEnumerable<Layout> Layouts
{
get
{
return this.CardLayouts.Select(cl => cl.Layout);
}
}
}

EntityFramework navigation property not working as expected

I have the following 3 (simplified) classes setup in entity framework
public class Service
{
[Key]
public int ServiceId { get; set; }
public int WorkformId { get; set; }
[ForeignKey("WorkformId")]
public virtual Workform Workform { get; set; }
}
public class Workform
{
[Key]
public int WorkformId { get; set; }
[ForeignKey("WorkformId")]
public virtual ICollection<FieldMap> FieldMaps { get; set; }
}
public class FieldMap
{
[Key]
public int FieldMapId{ get; set; }
public int WorkformId{ get; set; }
}
And if I try to do something like this
var service = db.Services.Include("Workform.FieldMaps")
.FirstOrDefault(p => p.ServiceId == serviceId);
service.Workform.FieldMaps is pulling the entire collection, not just the records with the matching relational id.
Am I missing some here?

Asp.Net MVC Reaching The Property Using Many To Many Relation With Mapping Table

You can see my previous question which related with many to many relation but with auto generated mapping table.
I have 2 model, HrTraining and HrPerson. Any people can be assigned to one or more Trainings. You can see my model as below
public class HrTraining
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HrMapTrainingPerson> HrMapTrainingPerson { get; set; }
}
public class HrMapTrainingPerson
{
public int Id { get; set; }
public string Status { get; set; }
public int HrTrainingId { get; set; }
public int HrPersonId { get; set; }
public virtual HrTraining HrTraining { get; set; }
public virtual HrPerson HrPerson { get; set; }
}
public class HrPerson
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HrMapTrainingPerson> HrMapTrainingPerson { get; set; }
}
How can i take all training objects which assingned to a person with efficient way.
So you want to find a person, and get all the trainings assigned to it? There are lot of ways.. but using your models, this could be something like this
var trPersons = dbContext.HrPerson.Find(idPerson).HrMapTrainingPerson.ToList();
foreach(var trPerson in trPersons) {
var training = trPerson.HrTraining;
//do what you want, here you can get trPerson.HrTraining.Name for instance
}

Categories