I am trying to list some food items with a controller. I use Repository pattern with UnitOfWork for the data in another assembly and referenced it in a BaseApiController. The Data property is my UnitOfWork instance.
var result = Data.Food
.FindAll()
.Select(FoodItemViewModel.Create);
return result;
and here is my ViewModel:
public static Expression<Func<FoodItem, FoodItemViewModel>> Create
{
get
{
return fi => new FoodItemViewModel
{
Id = fi.Id,
Description = fi.Description,
DiaryEntries = fi.DiaryEntries
.Select(s => new DiaryEntityViewModel()
{
Id = s.Id,
Quantity = s.Quantity
}
};
}
}
But all I get is:
"The specified type member 'DiaryEntries' is not supported in LINQ to
Entities. Only initializers, entity members, and entity navigation
properties are supported."
My DiaryEntries member in the ViewModel is
IEnumerable<DiaryEntityViewModel>
and my DiaryEntries member in the Data instance is
IRepository<DiaryEntry>
and DiaryEntry is my model class
and here is my FoodItem model class:
public class FoodItem
{
private IEnumerable<Measure> measures;
private IEnumerable<DiaryEntry> diaryEntries;
public FoodItem()
{
this.measures = new HashSet<Measure>();
this.diaryEntries = new HashSet<DiaryEntry>();
}
public int Id { get; set; }
public string Description { get; set; }
public virtual IEnumerable<DiaryEntry> DiaryEntries
{
get
{
return this.diaryEntries;
}
set
{
this.diaryEntries = value;
}
}
public virtual IEnumerable<Measure> Measures
{
get
{
return this.measures;
}
set
{
this.measures = value;
}
}
}
Change you FoodItem class to the one below, IEnumerable<T> is not supported as a type for a navigation collection :
public class FoodItem
{
public FoodItem()
{
this.Measures = new HashSet<Measure>();
this.DiaryEntries = new HashSet<DiaryEntry>();
}
public int Id { get; set; }
public string Description { get; set; }
public virtual ICollection<DiaryEntry> DiaryEntries
{
get;
set;
}
public virtual ICollection<Measure> Measures
{
get;
set;
}
}
Related
I have one-to-many relationship database. DbSet Companies being "One" and DbSet Cases being "many". Here's my context and model classes:
Database Context
class CaseContext : DbContext
{
public DbSet<ParticipantCompany> Companies{ get; set; }
public DbSet<ParticipantPerson> Persons { get; set; }
public DbSet<LegalCase> Cases { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite("Data Source=Clients.db");
}
ParticipantCompany class inherits from Participant Class.
public class ParticipantCompany : Participant
{
public ParticipantCompany():this(false, "","","","") { }
public ParticipantCompany (bool isclient) : this(isclient, "","","","") { }
public ParticipantCompany(bool isclient, string name, string address, string inncompany, string ogrn) : base(isclient, SubjectType.Company)
{
Name = name;
Address = address;
InnCompany = inncompany;
Ogrn = ogrn;
}
public string InnCompany { get; set; }
public string Ogrn { get; set; }
}
public abstract class Participant
{
public Participant(bool isclient, SubjectType Type, string name, string address)
{
SubjType = Type;
IsClient = isclient;
Name = name;
Address = address;
}
public Participant(bool isclient, SubjectType Type ) : this(isclient, Type, "","")
{
}
public int Id { get; set; }
public SubjectType SubjType { get; private set; }
public bool IsClient { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public List<LegalCase> Cases = new List<LegalCase>();
}
LegalCase class represents "Many" in relationships
public class LegalCase
{
public LegalCase() : this("", CaseType.ArbGeneral){}
public LegalCase(string casefabula, CaseType casetype)
{
CaseFabula = casefabula;
CaseType = casetype;
}
public int Id { get; set; }
public string CaseFabula { get; set; }
public CaseType CaseType { get; set; }
//public ICaseParticipant Client { get; set; }
public int? CompanyId { get; set; }
public ParticipantCompany Company { get; set; }
public int? PersonId { get; set; }
public ParticipantPerson Person { get; set; }
}
Now here's the Query:
using(var db = new CaseContext())
{
var QClients = db.Companies
.Where(x => x.IsClient == true)
//Exception: The expression 'y.Cases' is
// invalid inside an 'Include' operation,
// since it does not represent a property
// access: 't => t.MyProperty'. etc
.Include(y => y.Cases)
.ToList();
}
I tried to explicitly cast y to ParticipantCompany since it's what the prompt of the exection seems to suggest:
To target navigations declared on derived types, use casting ('t => ((Derived)t).MyProperty') or the 'as' operator ('t => (t as Derived).MyProperty')
But it generates the same exception:
using(var db = new CaseContext())
{
var QClients = db.Companies
.Where(x => x.IsClient == true)
//Same exception
.Include(y => (y as ParticipantCompany).Cases)
.ToList();
}
Change Cases from being field to property as the exception suggests:
public List<LegalCase> Cases { get; set; } = new List<LegalCase>();
From the docs:
Each entity type in your model has a set of properties, which EF Core will read and write from the database. If you're using a relational database, entity properties map to table columns.
By convention, all public properties with a getter and a setter will be included in the model.
I would like to know, how could I, with AutoMapper, Map one Dto to multiple entities.
Lemme explain.
I've got one Dto, with an enum to describe its type (to avoid having multiple dtos)
Depending on that enum (RelationType here), I would like to map it to the correct Model (Entity, what ever, it's another object that I use in database).
public class BCardDto : IMappedDto
{
public long Id { get; set; }
public BCardRelationType RelationType { get; set; }
public long RelationId { get; set; }
}
Here are is my Model base:
public class BCardModel : IMappedDto
{
public long Id { get; set; }
}
And here the derived model :
public class CardBCardModel : BCardModel
{
// ormlite, ignore that
[Reference]
public CardModel Card { get; set; }
[ForeignKey(typeof(CardModel), ForeignKeyName = "fk_bcard_card")]
public long RelationId { get; set; }
}
How do I map my Dto to the correct Model depending on the enum i've given ?
(I don't wanna use Mapper.Map everywhere but I wanna let mapper do the runtime mapping job)
Here is how I do it for the Model -> Dto
cfg.CreateMap<CardBCardModel, BCardDto>()
.ForMember(s => s.RelationType, expression => expression.UseValue(BCardRelationType.Card))
.IncludeBase<BCardModel, BCardDto>();
Tell me if I do something wrong and explain me why please :)
Thanks by advance,
Blowa.
Let's say you have a setup wherein there is a base class and 2 classes which derive the base class:
public class ModelBase
{
public string Name { get; set; }
}
public class ModelOne : ModelBase { }
public class ModelTwo : ModelBase { }
Let's also say you have a DTO with an enum as below:
public class ModelDto
{
public string Name { get; set; }
public ModelType ModelType { get; set; }
}
public enum ModelType
{
One = 1,
Two = 2
}
So now the task is: How do I map the ModelDto to either ModelOne or ModelTwo depending on the value in ModelDto.ModelType property?
Here is how:
Mapper.Initialize(cfg => cfg.CreateMap<ModelDto, ModelBase>().ConstructUsing(x =>
{
switch (x.ModelType)
{
case ModelType.One:
return new ModelOne { Name = x.Name };
case ModelType.Two:
return new ModelTwo { Name = x.Name };
default:
throw new InvalidOperationException("Unknown ModelType...");
}
}));
Usage
var dto1 = new ModelDto { ModelType = ModelType.One, Name = "ModelOne" };
var dto2 = new ModelDto { ModelType = ModelType.Two, Name = "ModelTwo" };
var one = Mapper.Map<ModelBase>(dto1);
var two = Mapper.Map<ModelBase>(dto2);
Another way to do the mapping is by using dynamic:
public class PersonDto
{
public string Name { get; set; }
}
public class StudentDto : PersonDto
{
public int studentNumber { get; set; }
}
public class EmployeDto : PersonDto
{
public string EmployeId { get; set; }
}
public class Person
{
public string Name { get; set; }
}
public class Student : Person
{
public int StudentNumber { get; set; }
}
public class Employe : Person
{
public string EmployeId { get; set; }
}
Create Map by using:
Mapper.CreateMap<StudentDto, Student>();
Mapper.CreateMap<EmployeDto, Employe>();
Do the Mapping by:
try
{
var student = MapPerson((dynamic) studentDto);
var employe = MapPerson((dynamic) employeDto);
}
catch
{
throw new InvalidOperationException("Unknown ModelType...");
}
And define two Methods
public static Student MapPerson(StudentDto studentDto)
{
return Mapper.Map<StudentDto, Student>(studentDto);
}
public static Employe MapPerson(EmployeDto employeDto)
{
return Mapper.Map<EmployeDto, Employe>(employeDto);
}
The benefit is that you don't need a key and avoid the switch statement
How to correctly handle computed properties in EF model?
My try bellow will fail because of "The entity or complex type 'Invoice' cannot be constructed in a LINQ to Entities query."
Consider method "GetInvoice" as WebApi method with allowed querystring.
static void Main(string[] args)
{
var invs = GetInvoice();
invs.FirstOrDefault();
}
public static IQueryable<Invoice> GetInvoice()
{
var model = new Model();
IQueryable<Invoice> inv = model.Invocies.Include(t => t.Items).SelectInvoiceData();
return inv;
}
public static class ExtHelper
{
public static IQueryable<Invoice> SelectInvoiceData(this IQueryable<Invoice> item)
{
return item.Select(c => new Invoice
{
LatestItemName = c.Items.FirstOrDefault().Name
});
}
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedAt { get; set; }
}
public class Invoice
{
public int Id { get; set; }
public DateTime CreatedAt { get; set; }
public string Issuer { get; set; }
[NotMapped]
public string LatestItemName { get; set; }
private ICollection<Item> _items;
public virtual ICollection<Item> Items
{
get { return _items ?? (_items = new Collection<Item>()); }
set { _items = value; }
}
}
EntityFramework 6 does not support creating partial entities like this. Either use anonymous type:
return item.Select(c => new
{
LatestItemName = c.Items.FirstOrDefault().Name
});
Or some DTO class that does not belong to context:
return item.Select(c => new InvoiceDTO
{
LatestItemName = c.Items.FirstOrDefault().Name
});
However in EF Core it is possible to create entities like in your example.
Have class Books and there i should implement two foreign tables. Comments and Rating. This is the class:
public class Books
{
public Books()
{
CommentsList = new List<Comments>();
}
public Books()
{
RatingList = new List<Rating>();
}
public virtual int Id { get; set; }
public virtual string Title { get; set; }
public virtual string Category { get; set; }
public virtual string ISBN { get; set; }
public virtual string Description { get; set; }
public virtual string Image { get; set; }
// public virtual int CategoryId { get; set; }
public virtual Categories Categories { get; set; }
public virtual IList<Comments> CommentsList { get; set; }
public virtual IList<Rating> RatingList { get; set; }
public virtual void AddComment(Comments comm)
{
comm.Books = this;
CommentsList.Add(comm);
}
public virtual void AddRating(Rating rating)
{
rating.Books = this;
RatingList.Add(rating);
}
}
It gives an error
Error 2 already defines a member called 'Books' with the same
parameter types
How to solve this to have possibility to add comments and rating to a book ?
You have the same constructor two times. I guess you're using Entity Framework and if I recall correctly, you want to change those ILists to ICollections to use the Entity Framework lazy-loading features.
Change
public class Books
{
public Books()
{
CommentsList = new List<Comments>();
}
public Books()
{
RatingList = new List<Rating>();
}
}
To :
public class Books
{
public Books()
{
CommentsList = new List<Comments>();
RatingList = new List<Rating>();
}
}
You simply can't have two constructors that have the same signature. You should consider using a builder pattern instead.
You would typically hide the constructors (make them private) and instead expose static methods like CreateFromComments and CreateFromRatings.
private Books() { }
public static Books CreateFromComments()
{
var ret = new Books();
ret.CommentsList = new List<Comments>();
return ret;
}
public static Books CreateFromRatings()
{
var ret = new Books();
ret.RatingsList = new List<Ratings>();
return ret;
}
may be you can pass a boolean param to set the list to initialize...
public Books(bool comments)
{
if (comments)
CommentsList = new List<Comments>();
else
RatingList = new List<Rating>();
}
I am developing a MVC Project with Entity framework and i have a category table like this :
public partial class Categories
{
public Categories()
{
this.Categories1 = new HashSet<Categories>();
}
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public Nullable<int> RelatedCategoryId { get; set; }
public virtual ICollection<Categories> Categories1 { get; set; } //Children
public virtual Categories Categories2 { get; set; } //Parent
}
When i get table data with EF, it gives me the object i want. Parents with children.
class Program
{
static Entities db = new Entities();
static void Main(string[] args)
{
List<Categories> categories = db.Categories.Where(item => item.RelatedId == null).ToList();
}
}
With relatedId == null part, i get the main categories which has no parent.
There is no problem this far. But i want to cast categories object which ef returned to another class which is :
public class NewCategories
{
public int Id { get; set; }
public string Name { get; set; }
private List<NewCategories> _subCategories;
public NewCategories()
{
_subCategories= new List<NewCategories>();
}
public List<NewCategories> SubCategories { get { return _subCategories; } }
}
And i want new List<NewCategories> newCategories object.
How can i accomplish that?
Thanks.
I think you have to create a recursive method to convert Categories to NewCategories, something like this (I'm not sure if it works, but it's worth trying):
public NewCategories ConvertToNewCategories(Categories cat){
NewCategories nc = new NewCategories {Id = cat.CategoryId, Name = cat.CategoryName};
nc.SubCategories.AddRange(cat.Categories1.Select(c=>ConvertToNewCategories(c)));
return nc;
}
//Then
List<NewCategories> categories = db.Categories.Where(item => item.RelatedId == null)
.Select(item=>ConvertToNewCategories(item))
.ToList();