i have three content types an applicationRecord, an ApplicationDetailRecord and a CustomerPartRecord, my applicationRecord looks like:
public virtual int Id { get; set; }
public virtual int CustomerId { get; set; }
public virtual DateTime CreatedAt { get; set; }
public virtual ApplicationStatus Status { get; set; }
public virtual CustomerPartRecord customer { get; set; }
public virtual IList<ApplicationDetailRecord> Details { get; protected set; }
now in my applicationService i have a getApplications() function like so:
public IQueryable<ApplicationRecord> GetApplications()
{
return _applicationRepository.Table;
}
when this runs it is returning all ApplicationDetailRecords but not the CustomerRecord. I also have two foreign key defined in my migration file which are
SchemaBuilder.CreateForeignKey("Application_Customer", "ApplicationRecord", new[] { "CustomerId" }, "CustomerPartRecord", new[] { "Id" });
SchemaBuilder.CreateForeignKey("ApplicationDetail_Application", "ApplicationDetailRecord", new[] { "ApplicationRecord_Id" }, "ApplicationRecord", new[] { "Id" });
i cant see any reason why the customer record isnt being returned, am i missing anything? how would i get this working?
Ok found the answer, my customerId in ApplicationRecord needed to be Customer_Id, after this it all worked fine!
Related
I have created one asp.net mvc web api using Entity framework model, Which can update Single table in Single request. What i want is to update two tables(Having foreign key relationship) in single POST Request.
How I can achieve this?
What I have Done:-
1.Created Two Table tblEmployeeRecord & tblCountryName in sql server with EmployeeId as a primary key & foreign key respectively.
2.Employee table Model:-
public partial class tblEmployeeRecord
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string userName { get; set; }
public string userRole { get; set; }
}
3.Country Name table Model:-
public partial class tblCountryName
{
public int CountryId { get; set; }
public int EmployeeId { get; set; }
public string Country_Name { get; set; }
}
4.Created wrapper Model as follow:-
public class UserAndCountry
{
public tblEmployeeRecord UserRecord { get; set; }
public tblCountryName CountryRecord { get; set; }
}
5.ActionResult Method in Controller Which handles post request:-
[ResponseType(typeof(UserAndCountry))]
public IHttpActionResult PosttblEmployeeRecord(UserAndCountry tblEmployeeRecord)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.tblCountryNames.Add(tblEmployeeRecord.CountryRecord);
db.tblEmployeeRecords.Add(tblEmployeeRecord.UserRecord);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = tblEmployeeRecord.UserRecord.EmployeeId }, tblEmployeeRecord);
}
6.Note:-What is Happening:- When I don't define foreign key relationship in SQL Server between these two table, I am able to update both table but when i define foreign key relationship I am not able to update these tables What will be my request object in that case, Where I am going wrong?
7.My Current Request object:-
{
"CountryRecord":
{
"Country_Name": "AP"
},
"UserRecord":
{
"Name": "Test User",
"userName": "Test.User#mail.com",
"userRole": "Hr"
}
}
The power of entity framework is the navigation properties for relationships. So say your models were:
public partial class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string userName { get; set; }
public string userRole { get; set; }
// Foreign Key
public int CountryId { get; set; }
// Navigation Property
public virtual Country EmployeeCountry
}
public partial class Country
{
public int CountryId { get; set; }
public string Country_Name { get; set; }
}
Now your update becomes:
var employeeRecord = tblEmployeeRecord.UserRecord;
// add the country. EF will make the relationship automagically
employeeRecord.EmployeeCountry = tblEmployeeRecord.CountryRecord;
db.Employees.Add(employeeRecord);
db.SaveChanges();
I am not sure how to get the results from joining the tables in controllers.
There're 3 tables 'Groups' 'Users' 'GroupUser' (bridge table).
public class Group
{
[Key]
public int GroupID { get; set; }
public string Group_Name { get; set; }
public ICollection<User> Users { get; set; }
}
public class User
{
[Key]
public int UserID { get; set; }
public string User_Name { get; set; }
public ICollection<Group> Groups { get; set; }
}
I also have this EFContext class
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Group>()
.HasMany(g => g.Users)
.WithMany(u => u.Groups)
.Map(m =>
{
m.MapLeftKey("UserID");
m.MapRightKey("GroupID");
m.ToTable("GroupUSer");
});
Do I also need to build a GroupUser class (to represent the GroupUser bridge table)?
Then how do I get the results when joining the 3 tables to get list of groups and users?
GroupViewModel model = new GroupViewModel
{
Groups = .... // this should be a linq statement that get results
that contains all groups and users
};
The equal sql statemen would be
select *
from Group g
join GroupUser gu on g.GroupID=gu.GroupID
join User u on u.UserID=gu.UserID
No, intermediate class is not needed.
The main point of an ORM (Object-Relational Mapper, which is what Entity Framework is) is to abstract away the database and let you work in a pure object-oriented way. Intermediate tables are definitely a database term and are not needed here.
The only reason I can think of that may lead you to create an intermediate class is when you need a "payload" (an extra meta-data) on the association. For example:
public class User
{
public int Id { get; set; }
public int Email { get; set; }
public virtual ICollection<Account> Accounts { get; set; }
}
public class Account
{
public int Id { get; set; }
public virtual ICollection<User> Users { get; set; }
}
Now, if you want the user-to-account association to define whether the association is of "Own the account" type (Administrator), you can do something like:
public class User
{
public int Id { get; set; }
public int Email { get; set; }
public virtual ICollection<AccountUserAssociation> Accounts { get; set; }
}
public class Account
{
public int Id { get; set; }
public virtual ICollection<AccountUserAssociation> Users { get; set; }
}
public class AccountUserAssociation
{
public virtual User User { get; set; }
public virtual Account Account { get; set; }
public AssociationType AssociationType { get; set; }
}
public enum AssociationType { Regular, Administrator }
I can't wrap my mind around this issue and haven't found the correct search keys yet:
I would like to have several categories of items in which all items have specific attributes. Those attributes (text fields, dropdowns, or checkboxes) should be added to a category and I want to edit and save those attributes for each item.
I'm working with MVC 4 and code-first EF5. How can I implement this?
My first approach were several classes like Text, Dropdown that were inherited from an abstract Attribute class and a Category class like this:
public class Category
{
[Key]
public int CategoryId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Item> Items { get; set; }
public virtual ICollection<Attribute> Attributes { get; set; }
}
But then I had no idea to proceed. Am I on the right way or completely wrong? Can someone give me a few hints I can search for?
Edit
Ultimately I'm trying to build a list of hifi devices. Speakers have different attributes than amplifier and those have different attributes to tape recorders. I would like to give a unified look for the details of each device and pre-define specific attributes to that category with an additional free-for-all text area. Speaker XYZ is my item, Speaker my category and dB an attribute.
Ok so this question is basically about the data design.
First, I assume that the rule is:
One item has one category
One category has many attributes
One item has many attributes associated with the category
For rule no.1, it is good enough in your design. (simplified example)
public class Category{
public IEnumerable<Item> Items{get;set;}
}
public class Item{
public Category Category{get;set;}
}
Its clear enough.
For rule no.2, I think you should make a CategoryAttribute class. It holds the relation between one to many Category and Attribute. Basically, CategoryAttribute is a master, whereas the children will be ItemAttribute.
public class Category{
public IEnumerable<CategoryAttribute> CategoryAttributes{get;set;}
}
public class CategoryAttribute{
public Category Category{get;set;}
public string CategoryName{get;set;}
public string DefaultValue{get;set;} // maybe a default value for specific
// attribute, but it's up to you
public IEnumerable<ItemAttribute> ItemAttributes{get;set;}
}
The IEnumerable<ItemAttribute> is the one to many relation between category attribute and item attribute.
For rule no.3, the the ItemAttribute described in rule no.2 will be represented attribute owned by each item.
public class Item{
public IEnumerable<ItemAttribute> ItemAttributes{get;set;}
}
public class ItemAttribute{
public Item Item {get;set;} // it owned by one attribute
public CategoryAttribute{get;set;} // it owned by one category attribute
}
I don't quite sure about how to represent relation or primary and foreign key in code first. Hopefully I can enhance my answer if needed (and if I able). But hopefully my illustration about relations and the class designs for each objects.
I think something like this may work for you...
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Item> Items { get; set; }
public virtual ICollection<Attribute> Attributes { get; set; }
}
public class Item
{
public int ItemId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
public virtual ICollection<ItemAttribute> ItemAttributes { get; set; }
}
public class Attribute
{
public int AttributeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<ItemAttribute> ItemAttributes { get; set; }
}
public class ItemAttribute
{
public int ItemId { get; set; }
public int AttributeId { get; set; }
public Item Item { get; set; }
public Attribute Attribute { get; set; }
public string Value { get; set; }
public int ValueInt{ get; set; }
// etc.
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ItemAttribute>()
.HasKey(x => new { x.ItemId, x.AttributeId });
modelBuilder.Entity<ItemAttribute>()
.HasRequired(x => x.Item)
.WithMany(x => x.ItemAttributes)
.HasForeignKey(x => x.ItemId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<ItemAttribute>()
.HasRequired(x => x.Attribute)
.WithMany(x => x.ItemAttributes)
.HasForeignKey(x => x.AttributeId)
.WillCascadeOnDelete(false);
// AttributeCategories is created for you - but you can do the same as ^ above to customize
// just change 'ICollection<Category> Categories' to collection of 'ItemAttribute'
}
// use it like e.g.
var item = new Item { Name = "ItemTest", };
var attribute = new Attribute { Name = "attributeTest", };
item.ItemAttributes = new List<ItemAttribute>
{
new ItemAttribute { Item = item, Attribute = attribute, Value = "test", },
};
var category = new Category
{
Name = "cat1",
Items = new[]
{
item,
new Item{ Name = "Item1", },
new Item{ Name = "Item2", },
new Item{ Name = "Item3", },
new Item{ Name = "Item4", },
new Item{ Name = "Item5", },
},
Attributes = new[]
{
attribute,
new Attribute{ Name = "att1", },
new Attribute{ Name = "att2", },
}
};
db.Categories.Add(category);
db.SaveChanges();
var categories = db.Categories.ToList();
ItemAttribute is used to connect and store values.
And you're going to need to further adjust as per your requirements.
I actually never worked with code first approach, but I can give you some idea about how this scenario can be handled...To me, it looks that Item is the major one instead of Category. So you can have this structure...
public class Category
{
[Key]
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public string CategoryDescription { get; set; }
// use attributes here if you want them for Category
//public Dictionary<string, string> ItemnAttributes { get; set; }
}
public class MyItem
{
[Key]
public int ItemId { get; set; }
public string ItemName { get; set; }
public string ItemDescription { get; set; }
public Category ItemnCatagory { get; set; }
public Dictionary<string, string> ItemnAttributes { get; set; }
}
Hope this helps..
I'm traying to do a mapping with One to One relationship with id as "foreign", I can't change the database
Those are the tables
Cutomer
int CustomerId
string Name
CustomerDetail
int CustomerId
string Details
Entity Splittitng does not works for me since i need a left outter join.
Any Ideas?
Thanks in advance,
and sorry about my english.
You can use the Shared Primary Key mapping here.
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public virtual CustomerDetail CustomerDetail { get; set; }
}
public class CustomerDetail
{
public int CustomerId { get; set; }
public string Details { get; set; }
public virtual Customer Customer { get; set; }
}
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CustomerDetail>().HasKey(d => d.CustomerId);
modelBuilder.Entity<Customer>().HasOptional(c => c.CustomerDetail)
.WithRequired(d => d.Customer);
}
}
I am starting out with using the EF Code First with MVC and am a bit stumped with something. I have the following db structure (Sorry but I was not allowed to post an image unfortunately):
Table - Products
Table - RelatedProducts
1-Many on Products.ProductID -> RelatedProducts.ProductID
1-Many on Products.ProductID -> RelatedProducts.RelatedProductID
Basically I have a product that can have a series of products that are related to it. These are kept in the RelatedProducts table with the relationship defined by the ProductID and the ProductID of the related product which I have named RelatedProductID. In my code I has produced the following classes:
public class MyDBEntities : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<RelatedProduct> RelatedProducts { get; set; }
}
public class Product
{
public Guid ProductID { get; set; }
public string Name { get; set; }
public string Heading { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public Guid CategoryID { get; set; }
public string ImageURL { get; set; }
public string LargeImageURL { get; set; }
public string Serves { get; set; }
public virtual List<RelatedProduct> RelatedProducts { get; set; }
}
public class RelatedProduct
{
public Guid ProductID { get; set; }
public Guid RelatedProductID { get; set; }
public virtual Product Product { get; set; }
public virtual Product SimilarProduct { get; set; }
}
I then try to access these in code using:
myDB.Products.Include("RelatedProducts").Where(x => x.ProductID == productID).FirstOrDefault();
But I keep getting the following error:
{"Invalid column name 'ProductProductID2'.\r\nInvalid column name 'ProductProductID2'.\r\nInvalid column name 'ProductProductID'.\r\nInvalid column name 'ProductProductID1'.\r\nInvalid column name 'ProductProductID2'."}
What am I doing wrong? I basically want to get a product then iterate through the RelatedProducts and display that product info.
The first part of the answer is that EF4 CTP5 is not correctly mapping your POCOs to the database because it's not smart enough. If you check out the database, you get:
CREATE TABLE RelatedProducts(
RelatedProductID uniqueidentifier NOT NULL,
ProductID uniqueidentifier NOT NULL,
ProductProductID uniqueidentifier NULL,
ProductProductID1 uniqueidentifier NULL,
ProductProductID2 uniqueidentifier NULL,
PRIMARY KEY CLUSTERED
(
RelatedProductID ASC
)
) ON [PRIMARY]
Yuck! This needs to be fixed with some manual work. In your DbContext, you add rules like so:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.Property(p => p.ProductID)
.HasDatabaseGenerationOption(DatabaseGenerationOption.Identity);
modelBuilder.Entity<RelatedProduct>()
.HasKey(rp => new { rp.ProductID, rp.RelatedProductID });
modelBuilder.Entity<Product>()
.HasMany(p => p.RelatedProducts)
.WithRequired(rp => rp.Product)
.HasForeignKey(rp => rp.ProductID)
.WillCascadeOnDelete();
modelBuilder.Entity<RelatedProduct>()
.HasRequired(rp => rp.SimilarProduct)
.WithMany()
.HasForeignKey(rp=> rp.RelatedProductID)
.WillCascadeOnDelete(false);
base.OnModelCreating(modelBuilder);
}