I have a many to many relationship in my application and I'm using Entity code first so it looks like this (there is obviously more to it, but this is the basic structure):
Class Ingredient{
int Id {get; set;}
string Label {get; set;}
}
Class RecipeIngredient{
Ingredient Ing {get; set;}
Recipe Rec {get; set;}
int Quantity {get; set;}
}
class Recipe{
int Id {get; set;}
List<RecipeIngredient> RecIngs {get; set;}
}
How do I handle the mapping to map this to the following DTO:
class RecipeDTO{
List<IngredientDTO> Ingredients;
}
class IngredientDTO{
int Id {get; set;}
string Label {get; set;}
int Quantity {get; set;}
}
Given that I already have the standard mappings:
Mapper.CreateMap<Recipe, RecipeDTO>();
Mapper.CreateMap<Ingredient, IngredientDTO>();
I assume I have to do some Mapper.CreateMap().ForMember() stuff, but I have no idea beyond that.
Edit: I added a couple properties to the RecipeIngredient class to make it more real world.
I figured it out.
Mapper.CreateMap<RecipeIngredient, IngredientDTO>()
.ForMember(dto => dto.Label, rc => rc.MapFrom(x => x.Ing.Label))
You have to do this for every property of Ingredient that maps to a property on IngredientDTO.
Related
I have to work off an existing Db & would like to use ServiceStack's OrmLite.
Thus I have created Poco classes, using OrmLite T4 templates.
ISSUE: I would like to save to a table which has multiple primary keys.
public partial class DbUserGroup
{
[Required]
public int Userid { get; set;} // this is a primary key
[Required]
public int Groupid { get; set;} // this is a primary key
public int Ranking { get; set;}
public bool Isprimary { get; set;}
}
Currently using Db.Save(userGroup) does not work. Is there any way of addressing this using ServiceStack's OrmLite.
Multiple primary keys don't exist. A multi-column primary key yes.
Please take a look on this link https://github.com/ServiceStack/ServiceStack.OrmLite#limitations
As it said
A potential workaround to support tables with multiple primary keys is to create an auto generated Id property that returns a unique value based on all the primary key fields
I resolved it by adding [PrimaryKey] to both properties.
public partial class DbUserGroup
{
[Required]
[PrimaryKey]
public int Userid { get; set;} // this is a primary key
[Required]
[PrimaryKey]
public int Groupid { get; set;} // this is a primary key
public int Ranking { get; set;}
public bool Isprimary { get; set;}
}
I am trying to implement the below scenario using Entity Framework 5, with code first approach.
Scenario: I have three tables say
Table1: { Id1, Title }
Table2: { Id2, Title }
Table3: { Id3, Title }
and single intermediate table storing many-to-many relationship between "Table1 &Table2" and "Table2 & Table3". Say,
TableIntermediate: { FK1, FK2 }
To specify the relation, On OnModelCreating(), I have specified two model builder:
modelBuilder.Entity<Table1>()
.HasMany(c => c.Table2s)
.WithMany(pc => pc.Table1s)
.Map(m =>
{
m.ToTable("TableIntermediate");
m.MapLeftKey("FK1");
m.MapRightKey("FK2");
});
modelBuilder.Entity<Table1>()
.HasMany(c => c.Table3s)
.WithMany(pc => pc.Table1s)
.Map(m =>
{
m.ToTable("TableIntermediate");
m.MapLeftKey("FK1");
m.MapRightKey("FK2");
});
Below are the entities defined:
public class Table1
{
public int Id1 {get; set;}
public string Title {get; set;}
public ICollection<Table2> Table2s { get; set; }
public ICollection<Table3> Table3s { get; set; }
}
public class Table2
{
public int Id2 {get; set;}
public string Title {get; set;}
public ICollection<Table1> Table1s { get; set; }
}
public class Table3
{
public int Id3 {get; set;}
public string Title {get; set;}
public ICollection<Table1> Table1s { get; set; }
}
The code compiles properly. But at runtime throwing the error:
{"Schema specified is not valid. Errors: \r\n(275,6) : error 0019: The EntitySet 'Table1Table2' with schema 'XXXX' and table 'TableIntermediate' was already defined. Each EntitySet must refer to a unique schema and table."}
As we are using the exiting database, we want to store both the relations into a single intermediate table. The only solution I found is to introduce a new mapping table. Please let me know if the scenario is possible without introducing the new mapping table.
public class Country : Item
{
public string Code
{get; set;}
public string CodePhone
{ get; set; }
public string Name
{get; set;}
public string Flag
{ get; set; }
public decimal? Latitude
{get; set;}
public decimal? Longitude
{get; set;}
public int RegionsCount
{get; set;}
[ForeignKey("DefaultCurrency")]
public int? DefaultCurrencyID
{get; set;}
public virtual Currency DefaultCurrency
{ get; set; }
public ContinentType ContinentType
{ get; set; }
public virtual ICollection<Property>
Properties
{get; set;}
public ICollection<CountryLocale>
CountryLocales
{ get; set; }
}
public class CountryLocale : ItemLocale
{
[ForeignKey("Country")]
public int CountryID
{get; set;}
public Country
Country
{get; set;}
public string FullName
{get;set;}
}
public TEntity Get(Expression<Func<TEntity, bool>> where, params string[] includes)
{
var model = this.DbSet;
foreach (var property in includes)
{
model.AsExpandable().Include(property);
}
return model.Where(where).FirstOrDefault();
}
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
Country country = this._CountryRepository.Get(p=>p.ID == this.CountryID, new string[] { "CountryLocales" });
Value cannot be null.
Parameter name: source
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: source
line : CountryLocale countrylo = country.CountryLocales.First();
i got this error when trying to desactivate lazyloading for performance reasons. how can i resolve the problem? thanks in advance.
As you disabled LazyLoading you need to manually load the child properties of your main object with Include
var country = db.Country.Include("CountryLocales");
The other way around would be:
Dont disable lazy load and use include in your queries.
Try including your child objects one by one until you feel the
performance is better.
Usually if you know you will iterate over a
child object you should use include in your query for that child
object.
remeber to include second level child if you need to access a property of that level... Include("Parent.Child")
I am starting to move some code over to EF4.1 and I am having a problem loading child classes.
I found this article and it looks like there's a way to map the child class but I was wondering if the ID columns in the parent class are required.
I thought it was "no code" to simply include a reference to the child class and the rest was taken care of.
Here's the current object model:
public class classMember
{
public int MemberID {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
}
public class classReservation
{
public int ReservationID {get; set;}
public classMember Member {get; set;}
}
But loading the classReservation just gives null Members.
Do I need to include a property for the MemberID in classReservation as well as in classMember? It seems redundant from a design point of view.
First of all, in order to have navigation properties from one entity to another, they must be declared as virtual in your POCO. So you would want this:
public class classReservation
{
public int ReservationID {get; set;}
public virtual classMember Member {get; set;}
}
This is because at runtime, EF actually subclasses your POCO using reflection. To make the navigation property work, it needs to be able to override it. This is why it has to be virtual.
To answer your second question, no, you do not need to have a "foreign key property" from the child entity to the parent entity. It helps EF, but is not necessary.
We are in the process of removing foreign key properties from our entity models. To do it, you still need to tell EF how to map the relationship in the db. This can be done in your DbContext class' OnModelCreating method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<classReservation>
.HasRequired(r => r.classMember)
.WithMany()
.Map(x => x.MapKey("MemberId"));
}
You could also use HasOptional, WithRequiredDependent, etc, depending on the cardinality and multiplicity of the relationship.
Say I'm creating a repository to store digital E-Books as shown in the interface below. This repository will store the actual text of the book, as well as the metadata that identifies the book (title, author, publisher, ISBN etc..).
public interface IBookRepository
{
void AddBook(Book newBook);
void DeleteBook(int bookId);
void UpdateBook(Book updatedBook);
Book GetBook(int bookID)
}
public class Book
{
public int BookId {get; set;}
public string Title {get; set;}
public string Author {get; set;}
public IList<Page> Contents {get; set}
}
public class Page
{
public int PageNumber {get; set;}
public string PageContent {get; set;}
}
In most cases I would not want to retrieve the entire text for the book, as that would be rather expensive. In most cases all I care about is the metadata, for example I may simply want to create a list of books. So would it be acceptable in regards to DDD to also allow an IBookRepository to have methods that return BookSummary objects? Book summary objects would include the metadata but not the actual contents of the book.
What about having an UpdateBook(BookSummary book) method? Say I want to update the Book.Rating property, but don't need/want to read the entire contents of the book from the repository to do this.
public interface IBookRepository
{
//Full Book Methods
void AddBook(Book newBook);
void DeleteBook(int bookId);
void UpdateBook(Book updatedBook);
Book GetBook(int bookID)
//BookSummary Methods
BookSummary GetBookSummary(int bookID)
IEnumerable<BookSummary> GetBooksByAuthor(string authorName);
IEnumerable<BookSummary> GetBooksByGenre(int genreId);
void UpdateBook(BookSummary bookSummary);
}
public class BookSummary
{
public int BookId {get; set;}
public string Title {get; set;}
public string Author {get; set;}
public int PageCount {get; set;}
}
Note: I know using an ORM with Lazy Loading would also be a solution to this, but I'd like to design my repositories with out the assuming that lazy loading will be used
If there is a use case in your Domain that would support it why don't just create additional entity BookSummary with its own Repository that will do the job? It does not really matter where BookSummary is persisted - that it not relevant for the Domain.
It is important to derive Entities from the Domain using Ubiquitous language and not to look at the database structure.
public interface IBookRepository
{
//Full Book Methods
void Add(Book Book);
void Delete(Book Book);
Book findById(int bookID)
}
public interface IBookSummaryRepository
{
//Full Book Summary Methods
void Add(BookSummary BookSum);
void Delete(BookSummary BookSum);
Book findById(int bookSummaryID)
}
If you Repository has methods update() or store() it is more likely DAO than repository by DDD: http://codebetter.com/iancooper/2011/04/12/repository-saveupdate-is-a-smell/
In DDD repository should work only with aggregate root. In your case, I suppose, BookSummary is just an entity inside of Book aggregate (of course, more accurate analysis is needed here), so should get Book via BookRepository and then traverse to BookSummary from aggregate root using lazy loading. Otherwise, you are not applying Domain Driven Design here
This is an old question, however there is no accepted answer so I will answer for the benefit of people landing here from Google. I run into the issue all the time as we have many summary screens that show partial information and /or information compiled from multiple entities. What I do is use separate read models as suggested by #xelibrion in the comments of his answer. I do not employ full CQRS, just simple read models with query methods only. So your BookRepository remains like so:
public interface IBookRepository
{
void AddBook(Book newBook);
void DeleteBook(int bookId);
void UpdateBook(Book updatedBook);
Book GetBook(int bookID)
}
And your BookSummary read model and its methods look like this:
public class BookSummary
{
public int BookId {get; set;}
public string Title {get; set;}
public string Author {get; set;}
public int PageCount {get; set;}
}
public interface IBookSummaryQueries
{
BookSummary GetBookSummary(int bookID)
IEnumerable<BookSummary> GetBooksByAuthor(string authorName);
IEnumerable<BookSummary> GetBooksByGenre(int genreId);
}
Note, there are no methods to update Book here, just querying