Ambiguous match found exception in BindingListView - c#

I keep getting this exception while using Andrew Davey's BindingListView (http://blw.sourceforge.net/). I am using ServiceStack OrmLite . My objects looks like this:
public class Category
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
}
and
public class Product
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[References(typeof(Category))]
public int CategoryId { get; set; }
public int ProductTypeId { get; set; }
[StringLength(50)]
public string Name { get; set; }
[Reference]
public Category Category { get; set; }
}
I have no idea how to pass this exception.
Edit
The exception occurs on the first line of the following code:
var products = dbConn.Select<Product>().OrderBy(p => p.Name).ToList();
var productsView = new BindingListView<Product>(products);
dgProducts.DataSource = productsView;

you have
product.Name
product.Category.Name
product.Id
product.Category.Id
when that lib does reflection to get Property, it gets 2 "Name".
code doesnt know, Which one do you want. Product.Name from or Product.Category.Name.
tldr: easy fix is to change one of properties names
public class Category
{
public int cId { get; set; }
public string cName { get; set; }
}
public class Product
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[References(typeof(Category))]
public int CategoryId { get; set; }
public int ProductTypeId { get; set; }
[StringLength(50)]
public string Name { get; set; }
[Reference]
public Category Category { get; set; }
}

Related

how to update the model class recipe?

I have two model classes Category and Recipe and their relationship in one to many. I want to Edit the Recipe and also change the category that the recipe belongs to.Thanks in advance.
public class CookContext : DbContext
{
public CookContext(): base("cookContext")
{
}
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Category> Categories { get; set; }
}
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Recipe> Recipes { get; set; }
}
public class Recipe
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Ingridients { get; set; }
public string Image { get; set; }
public Category category { get; set; }
}
[HttpPost]
[ValidateInput(false)]
public ActionResult EditRecipe(Recipe recipe, int? categoryName)
{
var category = context.Categories.Where(c => c.Id ==
(int)categoryName).FirstOrDefault();
context.Entry(recipe).State = EntityState.Modified;
recipe.category = category;
context.SaveChanges();
}
The error messages i get are:
1.
[DbUpdateException: An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types.
2.
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
Try by adding the field CategoryId to your Recipe class, also, the category property should begin with a capital "C".
The collection property should be marked virtual if you want the data to be lazy loaded (only loaded when needed) otherwise, you may load all recipes for a given category every time you make a query:
public class Recipe
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Ingridients { get; set; }
public string Image { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
}
If it doesn't work try by setting up the ForeignKey attribute:
public class Recipe
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Ingredients { get; set; }
public string Image { get; set; }
[ForeignKey("Category")]
public int CategoryId { get; set; }
public Category Category { get; set; }
}
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
}

Getting DbUpdateException when adding a row

I'm trying to add a record in a table, but it's not working. The error message tells me that I cannot insert an explicit value in identity column for ProductCategories, but I don't know that I'm doing that. Maybe there is something I'm not getting about entity navigation, or my models are somehow not correctly linked?
SqlException: Cannot insert explicit value for identity column in table 'ProductCategories' when IDENTITY_INSERT is set to OFF.
Cannot insert explicit value for identity column in table 'Products' when IDENTITY_INSERT is set to OFF.
System.Data.SqlClient.SqlCommand+<>c.b__108_0(Task result)
DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch+d__32.MoveNext()
This is the code that fails (at await _context.SaveChangesAsync();):
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> FrontPageProduct(ViewModelFrontPageProduct frontPageProduct)
{
var fpp = new FrontPageProduct()
{
ProductCategoryId = frontPageProduct.ProductCategoryId,
ProductId = frontPageProduct.ProductId,
SortOrder = 0
};
_context.Add(fpp);
await _context.SaveChangesAsync();
return View("Index", new { id = fpp.ProductCategoryId, tab = 2 });
}
These are the involved entity models:
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
public List<FrontPageProduct> InFrontPages { get; set; }
public List<ProductInCategory> InCategories { get; set; }
}
public class ProductCategory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int SortOrder { get; set; }
public string Title { get; set; }
[ForeignKey(nameof(ParentCategory))]
public int? ParentId { get; set; }
public ProductCategory ParentCategory { get; set; }
public ICollection<ProductCategory> Children { get; set; } = new List<ProductCategory>();
public List<ProductInCategory> ProductInCategory { get; set; }
}
public class FrontPageProduct
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int ProductCategoryId { get; set; }
public int ProductId { get; set; }
public int SortOrder { get; set; }
[ForeignKey("ProductId")]
public virtual Product Product { get; set; }
[ForeignKey("ProductCategoryId")]
public virtual ProductCategory ProductCategory { get; set; }
}
The debug inspection of the fpp-object shows that the values for ProductCategoryId and ProductId are correct:
Where is/are my mistake/s?
EDIT I added the suggested [Key] and [DatabaseGenerated(DatabaseGeneratedOption.Identity)] to all the models, but I still get the same error.
I think that the Id field is always set to be primary key as default in EF anyway.
EDIT 2 I tried adding [FromBody] in my controller method, but that only resulted in a blank screen, no error message, and no changes being made to the database.
EDIT 3 I added [ForeignKey("ProductId")] and [ForeignKey("ProductCategoryId")] to the FrontPageProduct model, but still get the same SqlException.
EDIT 4 These are the foreign keys of my four tables:
FrontPageProducts:
FK_FrontPageProducts_ProductCategories_ProductCategoryId
FK_FrontPageProducts_Products_ProductId
ProductCategories:
FK_ProductCategories_ProductCategories_ParentId
Products:
none
ProductsInCategories:
FK_ProductsInCategories_FrontPageProducts_FrontPageProductId
FK_ProductsInCategories_ProductCategories_ProductCategoryId
FK_ProductsInCategories_Products_ProductId
Looks like you don't need to set DatabaseGenerated attribute for "int Id" fields, it is a convention and assumed that it is Identity Column.
Btw, are you sure you are getting the same error? The imgur link does not work for me. Do you really need Product and ProductCategory on your FrontPage class, if you can easily comment them out and test, please do so, if not you can try setting the values for them like below.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> FrontPageProduct(ViewModelFrontPageProduct frontPageProduct)
{
var fpp = new FrontPageProduct()
{
ProductCategoryId = frontPageProduct.ProductCategoryId,
ProductId = frontPageProduct.ProductId,
Product = _context.Set<Product>().Find(frontPageProduct.ProductId),
ProductCategory = _context.Set<ProductCategory>().Find(frontPageProduct.ProductCategoryId),
SortOrder = 0
};
_context.Add(fpp);
await _context.SaveChangesAsync();
return View("Index", new { id = fpp.ProductCategoryId, tab = 2 });
}
Apply Key and DatabaseGenerated attributes to every Id column on your models, so EF knows that it is an identity column and it needs to get back the generated id value.
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
[InverseProperty("Product")]
public IEnumerable<FrontPageProduct> InFrontPages { get; set; }
public List<ProductInCategory> InCategories { get; set; }
}
public class ProductCategory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int SortOrder { get; set; }
public string Title { get; set; }
[ForeignKey(nameof(ParentCategory))]
public int? ParentId { get; set; }
public ProductCategory ParentCategory { get; set; }
public ICollection<ProductCategory> Children { get; set; } = new List<ProductCategory>();
public List<ProductInCategory> ProductInCategory { get; set; }
}
public class FrontPageProduct
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int ProductCategoryId { get; set; }
public int ProductId { get; set; }
public int SortOrder { get; set; }
[ForeignKey("ProductId")]
public virtual Product Product { get; set; }
[ForeignKey("ProductCategoryId ")]
public virtual ProductCategory ProductCategory { get; set; }
}
Edit: you should add navigation properties, just like I added above. Making them virtual also helps with lazy loading.
The Id field should be the primary key in the database so you can specify that in the entity models. - Add the [Key]
public class Product
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
public IEnumerable<FrontPageProduct> InFrontPages { get; set; }
public List<ProductInCategory> InCategories { get; set; }
}

ServiceStack OrmLite mapping with references not working

I'm trying out OrmLite to see if I can replace Entity Framework in my projects. The speed is quite significant on simple queries. But I tried to map/reference a [1 to many- relation and read the documentation + examined the test code from the github page but without success. This is my example. Is there something I've forgot or should do to get it working like Entity Framework?
Example
// EF: returns +15.000 records + mapped > product.StockItems (slow)
dbContext.Products.Include(x => x.StockItems).ToList();
// OrmLite: returns +100.000 records (NO mapping > product.StockItems)
db.Select<Product>(db.From<Product>().Join<StockItem>());
// OrmLite: +15.000 separate requests to sql server (bad workarround + slow)
foreach (var product in db.Select<Product>())
{
// manual mapping
product.StockItems = db.Select<StockItem>(x => x.ProductId == product.Id);
}
Product.cs
public class Product
{
public int Id { get; set; }
public ProductType ProductType { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int DisplayOrder { get; set; }
public bool LimitedToStores { get; set; }
public string Sku { get; set; }
public decimal Price { get; set; }
public decimal OldPrice { get; set; }
public decimal SpecialPrice { get; set; }
public decimal DiscountPercentage { get; set; }
public DateTime? DateChanged { get; set; }
public DateTime? DateCreated { get; set; }
//...
[Reference]
public virtual IList<StockItem> StockItems { get; set; } = new List<StockItem>();
}
StockItem.cs
public class StockItem
{
public int Id {get; set;}
[References(typeof(Product))]
public int ProductId { get; set; }
public string Size { get; set; }
public int TotalStockQuantity { get; set; }
public string Gtin { get; set; }
public int DisplayOrder { get; set; }
// ...
[Reference]
public virtual Product Product { get; set; }
}
Ideally your POCOs/DTOs shouldn't use interfaces and you don't need to use virtual as ORM only populates your own POCOs (i.e. it doesn't create proxies of your models like other Heavy ORMs), I also prefer to use [AutoIncrement] for integer Ids (unless you need to populate specific Ids) so my Models would look like:
public class Product
{
[AutoIncrement]
public int Id { get; set; }
public ProductType ProductType { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int DisplayOrder { get; set; }
public bool LimitedToStores { get; set; }
public string Sku { get; set; }
public decimal Price { get; set; }
public decimal OldPrice { get; set; }
public decimal SpecialPrice { get; set; }
public decimal DiscountPercentage { get; set; }
public DateTime? DateChanged { get; set; }
public DateTime? DateCreated { get; set; }
[Reference]
public List<StockItem> StockItems { get; set; }
}
public class StockItem
{
[AutoIncrement]
public int Id { get; set; }
[References(typeof(Product))]
public int ProductId { get; set; }
public string Size { get; set; }
public int TotalStockQuantity { get; set; }
public string Gtin { get; set; }
public int DisplayOrder { get; set; }
}
OrmLite's POCO References only populate 1-level deep and it's not a good idea to have cyclical relationships as they're not serializable so I'd remove the back reference on StockItems as it's not going to be populated.
You also need to use LoadSelect in order to query and return POCOs with references, so to return Product with their StockItem references you can just do:
db.LoadSelect<Product>();
You can also populate this manually with 2 queries by using Merge extension method to merge 2 disconnected record sets, e.g:
var q = db.From<Product>().Join<StockItem>();
var products = db.Select(q.SelectDistinct());
var stockItems = db.Select<StockItem>();
products.Merge(stockItems);
Which will merge Products with their StockItems which you can quickly see by running:
products.PrintDump();

Entity Framework 6 table with many foreign keys each pointing to different tables

I have Country, City, Region and "Account Address" tables.
I want to create foreign key columns in "Account Address" pointing to Country, City, Region tables.
I have this code but it throws an error on creating database
The property \u0027Account_Id\u0027 cannot be configured as a
navigation property. The property must be a valid entity type and the
property should have a non-abstract getter and setter. For collection
properties the type must implement
After New Edit
public class Cities
{
[Key]
public int City_Id { get; set; }
public string City_name { get; set; }
public int Country_Id { get; set; }
[ForeignKey("Country_Id")]
public Countries countries { get; set; }
}
public class Region
{
[Key]
public int Region_Id { get; set; }
public string Region_name { get; set; }
public int City_Id { get; set; }
[ForeignKey("City_Id")]
public Countries countries { get; set; }
}
public class Accounts
{
[Key]
public int Account_Id { get; set; }
public string Fullname { get; set; }
public string Email { get; set; }
public string password { get; set; }
public int Cell_phone { get; set; }
public string Role { get; set; }
public int? estate_office_Id { get; set; }
[ForeignKey("estate_office_Id")]
public Estate_office estate_office { get; set; }
public List<Ads> ads { get; set; }
}
public class Account_address
{
[Key]
public int Id { get; set; }
[ForeignKey("Account_Id"), Column(Order = 0)]
public int Account_Id { get; set; }
[ForeignKey("Country_Id"), Column(Order = 1)]
public int Country_Id { get; set; }
[ForeignKey("City_Id"), Column(Order = 2)]
public int City_Id { get; set; }
[ForeignKey("Region_Id"), Column(Order = 3)]
public int Region_Id { get; set; }
public Accounts accounts { get; set; }
public Countries countries { get; set; }
public Cities cities { get; set; }
public Region region { get; set; }
}
You need to define public properties as shown below on the Account_address class.Then only EF will know how to map those navigation properties correctly.
public class Account_address
{
......
......
public Accounts accounts { get; set; } //like this
public Countries countries { get; set; } //like this
public Cities cities { get; set; } //like this
public Region region { get; set; } //like this
}
Update :
Hence you're not using singular naming convention for the classes,you have encountered this issue.Either you have to change the name of classes as singular or need to change the navigational property names a shown below.You have to do this for all the places.Here I have shown only for the Accounts class related navigational property.
[ForeignKey("Accounts_Id"), Column(Order = 0)]
public int Accounts_Id { get; set; }
My Advice is to follow the basic naming conventions.Then you can avoid lot of above kind of weird errors.

Save complexa data using entity framework

Hi every one I want to save complex data using Entity Framework and C#. I have 2 classes Product and Order defined as follows
Product Class
public class Product
{
[Key]
public int Id { get; set; }
public string SKU_Code { get; set; }
public string Product_Name { get; set; }
public string Quantity { get; set; }
public string Price { get; set; }
public string Image { get; set; }
public DateTime Created_Date { get; set; }
public DateTime Modified_Date { get; set; }
}
Order Class
public class Order
{
[Key]
public long ID { get; set; }
public string Order_Id { get; set; }
public string Payment_Type { get; set; }
public string Customer_Name { get; set; }
public string Shipping_Address { get; set; }
public DateTime Order_Date { get; set; }
public DateTime Modified_Date { get; set; }
public bool Flag { get; set; }
public List<Product> ProductDetails { get; set; }
}
And I want to save data Order details and my piece of code is as follows.
public Order Add(Order odrerDetails)
{
using (var context = new EcommerceDBContext())
{
var MyOrder_Id = Helper.Random(7); //Generate random orderID from my class
foreach (var detail in odrerDetails.ProductDetails)
{
odrerDetails.Order_Id = MyOrder_Id;
odrerDetails.Quantity = Convert.ToInt32(detail.Quantity);
odrerDetails.Amount = Convert.ToDouble(detail.Price);
//Other Details
context.objOrderListing.Add(odrerDetails);
}
context.SaveChanges();
return odrerDetails;
}
}
This gives me perfect data but when it comes to context.SaveChanges(); it return's me error.
An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types.
To me you domain model seems all wrong. The order should just be used for grouping, its a typical e-commerce scenario.
When you get a receipt of your purchases, you get one receipt with every Item and price listed next to it. Its considered as one order of multiple things, not multiple orders of multiple things.
Reading your last comment, you cant have multiple orders with the same order id. Try to understand the domain first before trying to solve it with code. Also,you have no notion of a Customer with an Order.
public class Product
{
[Key]
public int Id { get; set; }
public string SKU_Code { get; set; }
public string Product_Name { get; set; }
public string Price { get; set; }
public string Image { get; set; }
public DateTime Created_Date { get; set; }
public DateTime Modified_Date { get; set; }
}
public class Order
{
[Key]
public long ID { get; set; }
public string Order_Id { get; set; }
public string Payment_Type { get; set; }
public string Customer_Name { get; set; }
public string Shipping_Address { get; set; }
public DateTime Order_Date { get; set; }
public DateTime Modified_Date { get; set; }
public bool Flag { get; set; }
public List<OrderLineItem> Items { get; set; }
}
public class OrderLineItem
{
[Key]
public long ID { get; set; }
public long Order_Id { get; set; }
public long Product_Id {get; set;}
public int Quantity {get; set;}
}

Categories

Resources