Indirect navigation field with EF4 - c#

I'm wondering if its possible to have a property/field in a class that is populated directly from a database. I know that directly implementing this would break design patterns, such as separation of concerns, but I'm hoping to have some configuration in the OnModelCreating function of my DbContext.
In the example below, given a Product, I'd like to find out on which PriceTables it appears:
public class PriceTable
{
public int ID { get; set; }
public HashSet<Price> Prices { get; set; }
public PriceTable()
{
Prices = new HashSet<Price>();
}
}
public class Price
{
public int ID { get; set; }
public double Value { get; set; }
public int ProductID { get; set; }
public virtual Product Product { get; set; }
public int PriceTableID { get; set; }
public virtual PriceTable PriceTable { get; set; }
}
public class Product
{
public int ID { get; set; }
public String Name { get; set; }
// This is what I'd like to achieve
/*
public HashSet<PriceTable> PriceTables {
get {
// and here, return something from the DB
}
}
*/
}
Just to clarify: my model is not like the one below, but it works on the same way (so that I need this separation of classes, with this "junction table").
AFAIK, using LINQ I could find the information I want with the following:
from p in Prices
where p.Product.ID == MY_PRODUCT_ID
select p.PriceTable
Which means that is the query I'd like to embed in my Product class!
Thanks in advance!

I accomplished my objectives by changing the model to match the following (with changes described as comments):
public class PriceTable
{
public int ID { get; set; }
public HashSet<Price> Prices { get; set; }
// New field, which allows me to query "all the Products in some PriceTable"
public IEnumerable<Product> Products
{
get
{
return Prices.Select(p => p.Product);
}
}
public PriceTable()
{
Prices = new HashSet<Price>();
}
}
public class Price
{
public int ID { get; set; }
public double Value { get; set; }
public int ProductID { get; set; }
public virtual Product Product { get; set; }
public int PriceTableID { get; set; }
public virtual PriceTable PriceTable { get; set; }
}
public class Product
{
public int ID { get; set; }
public String Name { get; set; }
// New field, previsouly automatically generated by EF4
public HashSet<Price> Prices { get; set; }
// New field, which allows me to query "all the PriceTables on which a Product appears"
public IEnumerable<PriceTable> PriceTables
{
get
{
return Prices.Select(p => p.PriceTables);
}
}
}

Related

Set up automapper one to many relationship in asp.net core

I am started using automapper in my simple project. I want to exactly following 'one-to-many-to-many' mapping :-
public class AppUser
{
public int Id { get; set; }
public string UniversityName { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Description { get; set; }
public int AppUserId { get; set; }
public AppUser AppUser { get; set; }
public ICollection<Postedpic> Postedpics { get; set; }
}
public class Postedpic
{
public int Id { get; set; }
public string Url { get; set; }
public string PublicId { get; set; }
public Post Post { get; set; }
public int PostId { get; set; }
}
Destination:
public class MemberDto
{
public int Id { get; set; }
public string UniversityName { get; set; }
public ICollection<PostDto> Posts { get; set; }
}
public class PostDto
{
public int Id { get; set; }
public string Description { get; set; }
public ICollection<PostedpicDto> Postedpics { get; set; }
}
public class PostedpicDto
{
public int Id { get; set; }
public string Url { get; set; }
public bool IsMain { get; set; }
}
For proceed with automapper I tried this:-
CreateMap<AppUser, MemberDto>()
.ForMember(dest=>dest.Posts,opt=>opt.MapFrom(src=>src.Posts.Select(x=>x.Description)))
.ForMember(dest=>dest.Posts,opt=>opt.MapFrom(src=>src.Posts.Include(x=>x.Postedpic).Select(x=>x.Postedpic.Url)))
.ForMember(dest=>dest.Posts,opt=>opt.MapFrom(src=>src.Posts.Include(x => x.Postedpic).Select(x=>x.Postedpic.PublicId)));
But I found this error:-
Also I don't understand my approach is right or wrong for proceeding automapper.
You have two issues here:
For the Include method, you need to import the right namespace:
using System.Data.Entity;
You then tell AutoMapper how to do its job. It's smart enough to map properties by name, so you don't need to do much here. You just need to tell it which types to map to:
CreateMap<Post, PostDto>();
CreateMap<PostedPic, PostedPicDto>();
CreateMap<AppUser, MemberDto>();
As for the context, it looks to me like you are using lazy loading and want to make sure the posts and pics are loaded. For this to work, you need to configure the original query with Include, prior to mapping. For instance:
var user = SomeContext.AppUsers
.Include(u => u.Posts)
.Include(u => u.Posts.Select(p => p.PostedPics))
.FirstOrDefault(u => u.Id == someId);
var userDto = mapper.Map<AppUser, MemberDto>(user);
Dont use automapper, or any other mapping framework. This is code smell.
Create an interface like:
public interface IMemberDtoCreator {
int GetId();
string GetUniversityName();
ICollection<PostDto> GetPosts();
}
public class MemberDto {
public int Id { get; set; }
public string UniversityName { get; set; }
public ICollection<PostDto> Posts { get; set; }
public MemberDto(IMemberDtoCreator creator) {
Id = creator.GetId();
UniversityName = creator.GetUniversityName();
Posts = creator.GetPosts();
}
}
public class AppUser : IMemberDtoCreator {
public int Id { get; set; }
public string UniversityName { get; set; }
public ICollection<Post> Posts { get; set; }
public int GetId() {
return Id;
}
public string GetUnivsersityName() {
return UniversityName;
}
public ICollection<Post> GetPosts(){
ICollection<PostDto> result = new ICollection<PostDto>();
foreach(Post post in Posts){
result.add(new PostDto(post)) // And repeat the interface implementation for PostDto and post, etc.
}
}
}
This is pseudo code, and I didn't check for compiling, but you get the idea, I am sure. This is better in every way imaginable.
(If you are worried about overwriting the implementation of your interfaces, simply write the implementations in a partial class. Then you can autogenerate the original "base" class forever, and never interrupt your interface implementations.

I try to make filter checkbox with razor

Can someone help my with business logic when I try to find products in my bd list with properties from ProductFilterVM or give my advice where I can find solution.
public class ProductFilterVM
{
public string? Name { get; set; }
// other properties relating to a product that you may want to display the view - e.g. Description
public IEnumerable<FilterCategoryVM>? FilterCategories { get; set; }
}
public class FilterCategoryVM
{
public int Id { get; set; }
public string? Name { get; set; }
public List<FilterSelectionVM>? Selections { get; set; }
}
public class FilterSelectionVM
{
public int Id { get; set; }
public string? Name { get; set; }
}

Is there a way to use multiple Filter parameters from different Entity in Entity Framework?

I'm Creating an Event Management asp.net core app, My Customer Entity is related with different Entities by many to many relations. know I want to filter my Customers depending on both Event Name and Main Category name Entities.
Here are my Entities
Customer
public class Customer
{
public int Id {get; set;}enter code here
public string Name { get; set; }
public IList<CustomerEvent> CustomerEvents { get; set; }
public IList<CustomerMainCategory> CustomerMainCategories { get; set; }
}
Event
public class Event
{
public int Id { get; set; }
public string EventName { get; set; }
public IList<CustomerEvent> CustomerEvents { get; set; }
}
CustomerEvent
public Class CustomerEvent
{
public int CustomerId { get; set; }
public Customer Customer { get; set; }
public int EventId { get; set; }
public Event Event { get; set; }
}
MainCategory
public class MainCategory
{
public int Id { get; set; }
public string MainCategoryName { get; set; }
public IList<CustomerMainCategory> CustomerMainCategories { get; set; }
}
CustomerMainCategory
public class CustomerMainCategory
{
public int CustomerId { get; set; }
public Customer Customer { get; set; }
public int MainCategoryId { get; set; }
public MainCategory MainCategory { get; set; }
}
I want to Filter Customers that have same main category in the specified event.
Thank You in advance!!
Something like this?
(untestet)
db.Customers.Where(
c => c.CustomerEvents.Any(ce => ce.Event.Id == x)
&& c.CustomerMainCategories.Any(mc => mc.MainCategory.Id == y)
).ToList();

How to CreatMap List of Object with appling conditions Automapper

I have Domain object ProductType. It contains parentproducttypeId column. If product type is a subset of another producttype that parentproducttypeId to set to that producttypeId.(ex: T-Shirt is a subset of Casual wears)
public class ProductType : IEntityBase
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int PerentProductTypeId { get; set; }
public int Active { get; set; }
public DateTime UpdatedOnUTC { get; set; }
}
In API view model I have two classes
public class ParentProductTypeModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<ChildProductTypeModel> ChildProductTypeList { get; set; }
public ParentProductTypeModel()
{
ChildProductTypeList = new List<ChildProductTypeModel>();
}
}
public class ChildProductTypeModel
{
public int Id { get; set; }
public string Name { get; set; }
}
I need to Map returned List of Product Type to this ParentProductTypeModel List with setting all subset lists according to there parentproducttypeId. If parentproducttypeId equals to 0 it is parentproduct.

Entity Framework Code First - Mapping a table to another with both single and multiple relations?

I am trying to set up a relationship where a Car can have multiple Testruns, as well as an optionally selected "active testrun".
public class Car
{
public int ID { get; set; }
public virtual TestRun ActiveTestRun { get; set; }
public virtual ICollection<TestRun> TestRuns { get; set; }
}
public class TestRun
{
public int ID { get; set; }
public double TopSpeed { get; set; }
public virtual Car ActiveCar { get; set; }
public virtual Car Car { get; set; }
}
I have been trying to use InverseProperties with or without ForeignKey-attributes but to no luck. What is the correct way to setup this kind of relation? TIA!
Ps. I think I tried mostly all of the combinations from this tutorial without getting it to work :(
http://www.entityframeworktutorial.net/code-first/inverseproperty-dataannotations-attribute-in-code-first.aspx
EDIT: The resulting DB-schema I would want is something like:
tbl_Cars:
ID, ActiveTestRunID[Nullable]
tbl_TestRuns:
ID, TopSpeed, CarID
This achieved the result that I wanted:
public class Car
{
public int ID { get; set; }
public int? ActiveTestRunID { get; set; }
public virtual TestRun ActiveTestRun { get; set; }
[InverseProperty("Car")]
public virtual ICollection<TestRun> TestRuns { get; set; }
}
public class TestRun
{
public int ID { get; set; }
public double TopSpeed { get; set; }
public int CarID { get; set; }
public virtual Car Car { get; set; }
}

Categories

Resources