I am currently using OData V4 and wish to join 2 tables Account and Product:
The tables are as follows:
Account: Id, Name, Address, ColorCode,
Product: Id, AccountId
AccountId in the Product table is a foreign key mapped to the Id field in the Account table
In my builder I have :
var ProductType= builder.EntityType<Product>();
When I build the Product entity I wish to get the "ColorCode" values from the Account entity.
How can i establish this relationship in the model builder?
I would like the product class to look like this:
public class Product
{
public string Id { get; set; }
public string AccountId { get; set; }
public string ColorCode { get; set; }
}
OData enables you to define relationships between entities. It seems that you're using Web API 2.2 for OData V4 to write your service. In this case you can build the relationship between Products and Accounts like this:
Firstly, in the definition of your POCO classes for Products, you need to add a navigation property for its account(s):
public class Product{
public int Id {get;set;}
public string AccountId {get;set;}
public Account Account {get;set;} // define "Account" as a navigation property of Product
public class Account{
public int Id {get;set;}
public string Name {get;set;}
public Address Address {get;set;} // Address may be a complex type
public int ColorCode {get;set;}
}
Then in the class that inherit from the DbContext, add information about both entities in:
public virtual DbSet<Product> Products { get; set; }
public virtual DbSet<Account> Accounts { get; set; }
Finally in WebApiConfig.cs, you define the model using ODataConventionModelBuilder according to your need. The model builder will automatically recognize the relationship from the POCO classes and
generate the model for you.
After the service is built, on the client side, a client send such request to get the Product and the ColorCode of its Account:
GET http://host/service/Products?$expand=Account($select=ColorCode)
An example can be viewed here: http://services.odata.org/v4/(S(xrtmlkz1igiqidututicmb2t))/TripPinServiceRW/People?$expand=Trips($select=TripId)
Related
I have a contact class
[Table("Contacts")]
public class Contact
{
public string Id { get; set; }
public string Name { get; set; }
}
I have two classes inheriting from Contact:
[Table("Employees")]
public class Employee : Contact
{
public decimal Salary { get; set; }
}
[Table("Suppliers")]
public class Supplier : Contact
{
public string TIN { get; set; }
}
I am using Entity Framework 6.3 as my ORM.
Can I model something where the same contact can be both Employee and
Supplier with the same unique Id.
Employee emp = new Employee();
emp.Id = "C1";
emp.Name = "Employees";
emp.Salary = 10000;
emp.TrackingState = TrackingState.Added;
Supplier sup = new Supplier();
sup.Id = "C1";
sup.Name = "Employees";
sup.TIN = "ABC";
sup.TrackingState = TrackingState.Added;
When I do:
context.Employee.Add(emp);
context.Supplier.Add(sup);
context.Save();
Obviously, it will not allow me to add the record.
I get an error:
"Violation of PRIMARY KEY constraint 'PK_dbo.Contacts'. Cannot insert duplicate key in object 'dbo.Contacts'. The duplicate key value is (C1).\r\nThe statement has been terminated."
Can I make the Supplier also share the same Id as that of employee and
enable insert / update of employee and supplier?
Thanks
I assume you are not doing any specific inheritance mapping which by default will map this as Table per Hierarchy (TPH) inheritance. With this mapping you get a single Db table that contains the aggregate of all the fields in the base type and the dependent types with a discriminator field to know which type the row should be materialized. This allows for doing a query where you ask for a type.
With TPH each row can only be a single type, so you can not have the same row be both an Employee and Supplier.
There is another type of mapping you can do called Table Per Type (TPT) which will create a table for each type, so in your case 3, one for the shared fields, and one for each dependent type. This should allow for what you are asking about. (YMMV)
However, it seems to be that Employee and Supplier would be used in much different domains so I would suggest that you create your Contact table and relate it to both your employee and supplier.
[Table("Contacts")]
public class Contact
{
public string Id { get; set; }
public string Name { get; set; }
}
[Table("Employees")]
public class Employee
{
public string Id { get; set; }
public string ContactId { get; set; }
public decimal Salary { get; set; }
public Contact Contact { get; set; }
}
[Table("Suppliers")]
public class Supplier
{
public string Id { get; set; }
public string ContactId { get; set; }
public string TIN { get; set; }
public Contact Contact { get; set; }
}
Now you can query for an employee:
db.Employees.Include(e => e.Contact).First();
Or for a Supplier:
db.Employees.Include(e => e.Contact).First();
Which might be cleaner than the inheritence query you would need:
db.Contacts.OfType<Employee>().First();
In both the Has A modeling I show above and the Is A Modeling with TPT you are getting three tables. You just have the FK in what I show rather than the same ID in 3 tables with TPT.
There is also Table Per Class you can look at, which is similar to TPT but you don't get a table for the abstract/parent class, rather you get table for each dependent type with all the fields in it. I don't think this is what you want because it would have duplicate data, however, it does mean less joins.
I have created a model in the name of Sample with an Id and DocumentId property.In this I don't mention primary key for Id property.But it forms the primary key when I created the Sample as table in entity framework.I want to remove the primary key for Id. What do I have to do. Please help me. I am very new to mvc4.
public class Sample
{
[Required,DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
public int DocumentId { get; set; }
}
public override void Up()
{
CreateTable(
"dbo.Samples",
c => new
{
Id = c.Int(nullable: false, identity: false),
DocumentId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id);
}
I am putting this here as I don't think it will show up very well in comments :)
In the case of a user having many roles (and each role possibly being played by many users), you would have three tables linked to 2 classes. The tables would be a Users table with a unique UserId column and the rest of the user details. Another table would be Roles with a unique RoleId and the rest of the role information and a joining table that would have the id of the user and the id of the role he plays (this table could have a unique id of itself). If the user has 2 roles, they would have 2 records in the joining table, one for each of the roles. The classes would look something like this:
public class User{
public long UserId {get;set;}
public ICollection<Role> roles{get;set;}
//Other properties of the user name, DOb,etc.
}
public class Role{
public long RoleId{get;set;}
public ICollection<User> Users{get;set;}
//other properties of Role
}
This is a many to many relationship. Of course you could also have it as a one to many relationship if the role can be played by one user. In that case you don't need the joining table and you can just add a UserId column to the Role table and instead of a collection of users, the role would have a single property of type user (not really needed unless you want to navigate back from role to user).
Try adding the NotMapped attribute in your Id.
public class Sample
{
[Key]
public int SampleId {get;set;}
[Required,DatabaseGenerated(DatabaseGeneratedOption.None)]
[NotMapped]
public int Id { get; set; }
[Required]
public int DocumentId { get; set; }
}
EDIT:
I added a key attribute to specify your primary key.
You can also try this, which I think is better:
public class Sample
{
public int SampleId {get;set;}
public virtual ICollection<Document> Documents {get;set;}
}
public class Document
{
public int DocumentId {get;set;}
public int SampleId {get;set;}
public virtual Sample Sample {get;set;}
}
virtual keyword is for lazy loading.
Open the entity diagram (.edmx) file and find which ever property in that particular table is the primary key. Right click on it and select "properties". In the properties window see where it says StoreGeneratedPattern - Identity? Change that to none and save the diagram. It will regenerate the .cs model files by itself
Fluent API suppresses the Data Annotations in Entity framework. Data Annotation for Primary is [Key] and ID is by default Primary key with identity.
In that scenario, Delete(if it's there) Data Annotation of ID i:e;[KEY] and use Fluent API in your context class. In below example, my primary key is "CustomerName" due to Fluent. Example:
public class Customer
{
public int CustomerName { get; set; }
public int ID { get; set; }
[Required]
public string ProductID { get; set; }
}
In Context Class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>().HasKey(s => s.CustomerName);
}
I have a legacy table I need to connect my app to. I am using a code-first, POCO model. I have the following classes:
public class Equipment
{
[Key]
public string EquipmentId { get; set; }
public string OriginatorId { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
[Key]
[Column("employee_id")]
public string EmployeeId { get; set; }
public string EmployeeName { get; set; }
[ForeignKey("OriginatorEmployeeId")]
public virtual Equipment Equipment { get; set; }
}
I need to map EmployeeId in the Employee class to to OriginatorEmployeeId in the Equipment class.
Also, the legacy table is represented by the Employee class. The table is actually named employee (lower case) and the EmployeeId column is named "employee_id". I want to keep naming of my classes and properties consistent with the rest of the app, hence Employee and EmployeeId.
Here is what I have tried using fluent API:
modelBuilder.Entity<Employee>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("employee");
});
modelBuilder.Entity<Equipment>()
.HasOptional<Employee>(u => u.Employee)
.WithOptionalDependent(c => c.Equipment).Map(p => p.MapKey("OriginatorEmployeeId"));
I am probably mixing things I don't need to. The error I am getting right now is:
Multiplicity is not valid in Role 'Equipment_Employee_Source' in relationship 'Equipment_Employee'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
Any help is appreciated.
Can an employee record be associated to more than one equipment record? If they can then your Employee POCO should contain a collection property representing a one-to-many relationship between Employee and Equipment.
public virtual ICollection<Equipment> Equipments {get;set;}
You configuration should then be adjusted accordingly to show this relationship:
modelBuilder.Entity<Employee>()
.HasMany<Equipment>(u => u.Equipments)
.WithRequired(c => c.Employee).HasForeignKey(p => p.OriginatorId);
It also looks like you will need to setup a configuration for your column name mappings as well. Therefore, I would recommend that you create a separate configuration file for each of your POCOs to make it easier to manage the configurations, then just add those configurations to the modelbuilder.Configurations collection in your OnModelCreating event of your DBContext
public class EmployeeConfiguration : EntityTypeConfiguration<Employee>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelbuilder.Configurations.Add(new EmployeeConfiguration());
}
(Running EntityFramework 4.1)
I have a ASP .NET MVC 3 project that has a database with two database tables.
The models that express the database tables:
public class MyDetails
{
public int DetailsID {get;set;}
public string Description {get;set;}
public int
public CarID {get;set;}
public virtual Cars Cars {get;set;}
public PreviousCarID {get;set;}
}
public class Cars
{
public int CarsID {get;set;}
public string CarsName {get;set;}
}
Entity Framework will nicely relate the MyDetails.CarsID and the Cars.CarsID so that I can pull the CarsName.
The issue is that I'm not sure how to relate PreviousCarID to the Cars table.
What I've tried (results in an Entity Framework error):
public PreviousCarID{get;set;}
[ForeignKey("PreviousCarID")]
public virtual Cars Cars2 {get;set;}
I would rename Cars to Car, and change CarsID to CarID. Then leave in your DbContext the DbSet as type Car, but named Cars.
Second, to address your specific problem (using my recommendation above)
public class MyDetails
{
public int DetailsID {get;set;}
public string Description {get;set;}
public int CarID {get;set;}
public int PreviousCarID {get;set;}
public virtual Car Car {get;set;}
public virtual Car PreviousCar {get;set;}
}
public class Car
{
public int CarID {get;set;}
public string CarName {get;set;}
}
You don't say whether you are using Code First, Model First, or Database First. I'll assume Database First. If that's the case, then you need to make sure that both CarID and PreviousCarID are foreign keys to the Car table.
I've been trying to create model in EF 4.1 to represent a database schema with a single table and column holding foreign keys from two other tables, but have had little luck with both annotations and the fluent API. A sample model is shown here:
public class User
{
...
public virtual ExtendedAttribute ExtendedAttributes { get; set; }
}
public class Account
{
...
public virtual ExtendedAttribute ExtendedAttributes { get; set; }
}
public class ExtendedAttribute
{
public Guid Id {get; set;}
public Guid ItemId {get; set;} // both Account.Id and User.Id stored here
public string Value { get; set; }
}
Currently the configuration for these entities looks something like this for both User and Account modelBuilders:
this.HasOptional(u => u.ExtendedAttributes).WithRequired();
Any thoughts on how to do achieve? Many thanks.
It is even not possible with the database itself and EF will not put any abstraction for that. You must have separate column and navigation property for each entity.