Select Max() with GroupBy, using linq method syntax, EF - asp.net

I have a bunch of classes with some data:
public class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime bDate { get; set; }
//One-to-one with course
public int CourseId { get; set; }
public virtual Course Course { get; set; }
}
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection <Student_Course> Student_Courses { get; set; }
public int TeacherId { get; set; }
public virtual Teacher Teacher { get; set; }
}
public class Grade
{
public int Id { get; set; }
public int Mark { get; set; }
//one-to-many with Student_Course
public int Student_CourseId { get; set; }
public Student_Course Student_Course { get; set; }
}
public class Student_Course
{
public int Id { get; set; }
//many-to-many with student
public int StudentId { get; set; }
public virtual Student Student { get; set; }
//many-to-many with course
public int CourseId { get; set; }
public virtual Course Course { get; set; }
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime bDate { get; set; }
//one-to-many with student_course
public virtual ICollection <Student_Course> Student_Courses { get; set; }
}
Now i trying to write a query - for everyone teacher(name) needs to output his best student(name) by student mark, and the best mark, from class Grades, my code:
public IActionResult Task9()
{
var task9 = Db.Grades.GroupBy(gr => gr.Student_Course.Course.Teacher.Name).Select(x => new Task9
{
NameOfSt = x.Select(st => st.Student_Course.Student.Name).FirstOrDefault(),//Needs to correct this line
NameOfTeac = x.Select(r => r.Student_Course.Course.Teacher.Name).FirstOrDefault(),
BestMark = x.Max(gr => gr.Mark)
//NameOfSt = Db.Students.FirstOrDefault(st => st.Id ==x.FirstOrDefault().Student_Course.StudentId).Name
});
return View(task9);
}
So that code output correct teacher name and best mark on the course from students. But the student name is actually wrong. How can i fix that? Thanks for any help.
Teac
BestMark
NameStud

You could use OrderByDescending by Mark before select student name:
var task9 = Db.Grades.GroupBy(gr => gr.Student_Course.Course.Teacher.Name).Select(x => new Task9
{
NameOfSt = x.OrderByDescending(st => st.Mark).Select(st => st.Student_Course.Student.Name).FirstOrDefault(),//Needs to correct this line
NameOfTeac = x.Select(r => r.Student_Course.Course.Teacher.Name).FirstOrDefault(),
BestMark = x.Max(gr => gr.Mark)
});

Within the GroupBy you need to use the value of the grouping (in this case x) to select the Grade object with the highest Grade. In the code below, I get the bestGrade object by ordering by the Mark in descending order and then taking the first entry and then I take the student, name and best mark from that object:
public IActionResult Task9()
{
var task9 = Db.Grades.GroupBy(gr => gr.Student_Course.Course.Teacher.Name).Select(x =>
{
var bestGrade = x.OrderByDescending(y => y.Mark).First();
return new Task9
{
NameOfSt = bestGrade.Student_Course.Student.Name,//Needs to correct this line
NameOfTeac = bestGrade.Student_Course.Course.Teacher.Name,
BestMark = bestGrade.Mark
};
});
return View(task9);
}

Related

Receiving AutoMapperMappingException

Currently I'm creating a new feature. It looks simple, but I am stuck at a problem with automapping dto to another one.
I have to create a wishlist [adding /deleting items of wishlist].
All works fine, except one thing: while adding an item to the wishlist, I'm get a message like this:
"type": "AutoMapperMappingException",
"message": "Error mapping types..."
However, I can see it got inserted into the database. Also, can delete it too. I understand the problem is linked to Automapper, but I could not figure out how to map correctly.
[HttpPost]
public async Task<IActionResult> Add(WishListItemCreationDto wishListItemDto)
{
var itemAdd = _mapper.Map<WishlistItemDto>(wishListItemDto);
var itemCreated = await _wishListItemService.AddAsync(itemAdd);
return CreatedAtAction(nameof(GetId), new { id = itemCreated.Id }, wishListItemDto);
}
//service
public async Task<WishlistItemDto> AddAsync(WishlistItemDto item)
{
var entity = _mapper.Map<WishlistItem>(item);
var entityDetails = await _productDetailsRepository.GetById(item.ProductDetailId);
entity.ProductDetails = entityDetails;
await _wishListItemRepository.AddAsync(entity);
return _mapper.Map<WishlistItemDto>(entity);
}
DTOs:
public class WishListItemCreationDto
{
[Required]
public string CustomerId { get; set; }
[Required]
public int ProductDetailId { get; set; }
[Min(1)]
[Required]
public int Quantity { get; set; }
}
public class WishlistItemDto
{
public int Id { get; set; }
public string CustomerId { get; set; }
public int ProductDetailId { get; set; }
public ProductDetailsDtoWithPrimaryImage ProductDetails { get; set; }
public int Quantity { get; set; }
}
public class WishlistItem
{
public int Id { get; set; }
public string CustomerId { get; set; }
public Customer Customer { get; set; }
public int ProductDetailsId { get; set; }
public ProductDetails ProductDetails { get; set; }
public int Quantity { get; set; }
}
ProductDetails DTO:
public class ProductDetails
{
public int Id { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
public IList<ProductAttributeValue> ProductAttributes { get; set; } = new List<ProductAttributeValue>();
public int Quantity { get; set; }
public string Sku => $"BRD{Id}";
public byte[] RowVersion { get; set; } = new byte[0];
}
public class ProductDetailsDtoWithPrimaryImage
{
public int Id { get; set; }
public int Quantity { get; set; }
public int ProductId { get; set; }
public ProductDisplayEntity Product { get; set; }
public IEnumerable<ProductAttributeWithValueDto> ProductAttributes { get; set; }
public byte[] RowVersion { get; set; }
public string Sku => $"BRD{Id}";
public int? PrimaryImageId { get; set; }
}
AutoMapper:
public WishlistItemProfile()
{
CreateMap<WishlistItem, WishListItemCreationDto>().ReverseMap();
CreateMap<WishlistItemDto, WishListItemCreationDto>().ReverseMap();
CreateMap<WishlistItem, WishlistItemDto>()
.ForMember(wi => wi.ProductDetailId, opt => opt.MapFrom(f => f.ProductDetailsId))
.ForMember(wi => wi.ProductDetails, opt => opt.MapFrom(f => f.ProductDetails))
.ReverseMap();
}
everything is okay, but you missed inner mapping of your classes.
What the error says:
Mapping types:
ProductDetailsDtoWithPrimaryImage -> ProductDetails
SimpleWebApi.Controllers.ProductDetailsDtoWithPrimaryImage -> SimpleWebApi.Controllers.ProductDetails
Add additional mapping in your constructor WishlistItemProfile
CreateMap<ProductDetails, ProductDetailsDtoWithPrimaryImage>().ReverseMap();
And it starts works perfect

Entity Framework 6 - Null value in nested query with select

I am facing a problem in EF6. When I execute the query Select it return the value. But when I add Select it returns null.
The code is here:
The (W) is not null here...
var list = db.X.Include("Y").Include("Z.W")
.OrderBy(c => c.Id)
.Skip(pageSize * page)
.Take(pageSize)
.ToList();
Here, The W value is null...
var list = db.X.Include("Y").Include("Z.W")
.Select(a => new { a.Id, a.Z})
.OrderBy(c => c.Id)
.Skip(pageSize * page)
.Take(pageSize)
.ToList();
Please help :)
UPDATE 1
public class academy
{
public int Id { get; set; }
[StringLength(255)]
[Index(IsUnique = true)]
public string Name { get; set; }
public string Logo { get; set; }
[Required]
public Owner owner { get; set; }
public List<location> Location { get; set; }
}
public class location
{
public int Id { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }
public string City { get; set; }
public string Region { get; set; }
public string Neighborhood { get; set; }
public string Street { get; set; }
public academy Academy { get; set; }
public List<stadium> Stadiums { get; set; }
public List<Administrators> Administrators { get; set; }
public List<addition> Addition { get; set; }
public List<Pricing> Pricing { get; set; }
public List<time_frame> TimeFrames { get; set; }
[NotMapped]
public string Details {
get { return (City + " - " + Street); }
}
}
public class Pricing
{
public int Id { get; set; }
public double Price { get; set; }
public double? PriceAfterOffer { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public location Location { get; set; }
public players_capacity StadiumCapacity { get; set; }
}
public class players_capacity
{
public int Id { get; set; }
[StringLength(255)]
[Index(IsUnique = true)]
public string Capacity { get; set; }
}
var list = db.locations
.Select(a => new { a.Id, a.City, a.Region, a.Street, a.Latitude, a.Longitude, a.Pricing, a.Academy })
.OrderBy(c => c.Id)
.Skip(pageSize * page)
.Take(pageSize)
.ToList();
The problem is on players_capacity always null
Any additional data specified by Include is ignored if the query changes "shape", in this case your additional .Select expression invalidates the previous Include terms so they are ignored. The same happens if you do a GroupBy or GroupJoin.
Fortunately the fix is simple: explicitly specify the Y and Z.W members in your projection:
var list = db.X
.Select( x => new { x.Id, x.Z, x.Y, x.Z.W } )
.OrderBy( p => p.Id )
.Skip( () => pageSize * page )
.Take( () => pageSize )
.ToList();
(Note that I'm using the Expression<> overloads of Skip and Take, as those are better for use with EF).

Code-First Entity Framework Multiple Collections with Many to Many

I have another Entity Framework question here. I have a complicated object called Book and that object has a number of collections of type Contributor such as Writer, Letterer, Colorist, etc. Contributors are not necessarily scoped to a particular role though. So the same contributor (with the same ContributorId) could be both a Writer and a Colorist, for example.
public Book {
public ICollection<Contributor> Writers { get; set; }
public ICollection<Contributor> Artists { get; set; }
public ICollection<Contributor> Pencilers { get; set; }
public ICollection<Contributor> Inkers { get; set; }
public ICollection<Contributor> Colorists { get; set; }
public ICollection<Contributor> Letterers { get; set; }
public ICollection<Contributor> CoverArtists { get; set; }
public ICollection<Contributor> OtherContributors { get; set; }
}
public Contributor {
public int ContributorId { get; set; }
public string Name { get; set; }
}
I am having trouble, viewing the examples I have found here and on other sites, determining how I would signify the appropriate model. I would expect a Db Model something like this. What I want to avoid is a model wherein I have a separate table for every Contributor Role, or a separate row in the Contributor table for every instance in which a contributor is associated with a book in any role.
+ Books
--BookId
+ Contributors
--ContributorId
+ BookContributors
--BookId
--ContributorId
--Discriminator
I am such as ADO.NET guy that I am not really finding this too enjoyable, but I am determined to become at least borderline proficient in this important framework.
A Quick Note:
Since opening this question, I got pulled away at work and haven't had the time to thoroughly review the answers and play around with the results. But I didn't want to leave the bounty hanging as I appreciate the answers everyone has provided. So I selected the answer that appeared of the most interest to me starting out. I want to thank everyone though for this.
I have worked on a solution that implements the model you proposed although it works a bit different than what you would expect. Hope this answers your question.
Models
[Table("Book")]
public class Book
{
[Column("BookId")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int BookId { get; set; }
[NotMapped]
public ICollection<Contributor> Writers { get; set; }
[NotMapped]
public ICollection<Contributor> Artists { get; set; }
[NotMapped]
public ICollection<Contributor> Pencilers { get; set; }
[NotMapped]
public ICollection<Contributor> Inkers { get; set; }
[NotMapped]
public ICollection<Contributor> Colorists { get; set; }
[NotMapped]
public ICollection<Contributor> Letterers { get; set; }
[NotMapped]
public ICollection<Contributor> CoverArtists { get; set; }
[NotMapped]
public ICollection<Contributor> OtherContributors { get; set; }
}
[Table("Contributor")]
public class Contributor
{
[Column("ContributorId")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ContributorId { get; set; }
}
// Contributor Type is one of the following options: Writer, Artist, Penciler, etc.
[Table("ContributorType")]
public class ContributorType
{
[Column("ContributorTypeId")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ContributorTypeId { get; set; }
[Column("Name")]
public string Name { get; set; }
}
[Table("BookContributor")]
public class BookContributor
{
[Column("BookContributorId")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int BookContributorId { get; set; }
[Column("BookId")]
public int BookId { get; set; }
[Column("ContributorId")]
public int ContributorId { get; set; }
[Column("RoleId")]
public int RoleId { get; set; }
[ForeignKey("BookId")]
public virtual Book Book { get; set; }
[ForeignKey("ContributorId")]
public virtual Contributor Contributor { get; set; }
[ForeignKey("RoleId")]
public virtual ContributorType Role { get; set; }
}
Database Context
AppDbContext.cs:
public class AppDbContext : DbContext
{
public AppDbContext()
{
Database.SetInitializer<AppDbContext>(new AppDbInitializer());
}
public AppDbContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer<AppDbContext>(new AppDbInitializer());
}
public DbSet<Book> Books { get; set; }
public DbSet<Contributor> Contributors { get; set; }
public DbSet<ContributorType> ContributorTypes { get; set; }
public DbSet<BookContributor> BookContributors { get; set; }
}
AppDbInitializer.cs:
public class AppDbInitializer : DropCreateDatabaseAlways<AppDbContext>
{
protected override void Seed(AppDbContext context)
{
// default contributor types
var contributorTypes = new List<ContributorType>();
contributorTypes.Add(new ContributorType() { Name = "Writer" });
contributorTypes.Add(new ContributorType() { Name = "Artist" });
contributorTypes.Add(new ContributorType() { Name = "Penciler" });
contributorTypes.Add(new ContributorType() { Name = "Inker" });
contributorTypes.Add(new ContributorType() { Name = "Colorist" });
contributorTypes.Add(new ContributorType() { Name = "Letterer" });
contributorTypes.Add(new ContributorType() { Name = "CoverArtist" });
contributorTypes.Add(new ContributorType() { Name = "OtherContributor" });
// adding it to the context
foreach (var type in contributorTypes)
context.ContributorTypes.Add(type);
base.Seed(context);
}
}
Wrapping everything together
Program.cs:
class Program
{
static void Main(string[] args)
{
// enter name of the connection string in App.Config file
var connectionSettings = ConfigurationManager.ConnectionStrings["..."];
using (var dbContext = new AppDbContext(connectionSettings.ConnectionString))
{
// Creating a book
var book = new Book();
dbContext.Books.Add(book);
dbContext.SaveChanges();
// Creating contributor
var contributor = new Contributor();
dbContext.Contributors.Add(contributor);
dbContext.SaveChanges();
// Adding contributor to the book
var bookContributor = new BookContributor()
{
BookId = book.BookId,
ContributorId = contributor.ContributorId,
RoleId = dbContext.ContributorTypes.First(t => t.Name == "Writer").ContributorTypeId
};
dbContext.BookContributors.Add(bookContributor);
dbContext.SaveChanges();
// retrieving a book
var book = dbContext.Books.Where(b => b.BookId == 2).FirstOrDefault();
if (book != null)
{
book.Writers =
from contributor in dbContext.Contributors
join bookContributor in dbContext.BookContributors on contributor.BookId equals bookContributor.BookId
join contributorType in dbContext.ContributorTypes on contributorType.ContributorTypeId equals bookContributor.ContributorTypeId
where
bookContributor.BookId == 2 and
contributorType.Name == "Writer"
select contributor;
// do the same for other types of contributors
}
}
}
}
Create similar collections in the Contributor entity with M:N mapping and use the InverseProperty attribute to declare which collection in Contributor class corresponds with which collection in the Book class.
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Contributor> Writers { get; set; }
public virtual ICollection<Contributor> Artists { get; set; }
public virtual ICollection<Contributor> Pencilers { get; set; }
public virtual ICollection<Contributor> Inkers { get; set; }
public virtual ICollection<Contributor> Colorists { get; set; }
public virtual ICollection<Contributor> Letterers { get; set; }
public virtual ICollection<Contributor> CoverArtists { get; set; }
public virtual ICollection<Contributor> OtherContributors { get; set; }
public Book()
{
Writers = new List<Contributor>();
Artists = new List<Contributor>();
Pencilers = new List<Contributor>();
Inkers = new List<Contributor>();
Colorists = new List<Contributor>();
Letterers = new List<Contributor>();
CoverArtists = new List<Contributor>();
OtherContributors = new List<Contributor>();
}
}
public class Contributor
{
public int ContributorId { get; set; }
public string Name { get; set; }
[InverseProperty("Writers")]
public virtual ICollection<Book> WriterOfBooks { get; set; }
[InverseProperty("Artists")]
public virtual ICollection<Book> ArtistOfBooks { get; set; }
[InverseProperty("Pencilers")]
public virtual ICollection<Book> PencilerOfBooks { get; set; }
[InverseProperty("Inkers")]
public virtual ICollection<Book> InkerOfBooks { get; set; }
[InverseProperty("Colorists")]
public virtual ICollection<Book> ColoristOfBooks { get; set; }
[InverseProperty("Letterers")]
public virtual ICollection<Book> LettererOfBooks { get; set; }
[InverseProperty("CoverArtists")]
public virtual ICollection<Book> CoverArtistOfBooks { get; set; }
[InverseProperty("OtherContributors")]
public virtual ICollection<Book> OtherContributorOfBooks { get; set; }
public Contributor()
{
WriterOfBooks = new List<Book>();
ArtistOfBooks = new List<Book>();
PencilerOfBooks = new List<Book>();
InkerOfBooks = new List<Book>();
ColoristOfBooks = new List<Book>();
LettererOfBooks = new List<Book>();
CoverArtistOfBooks = new List<Book>();
OtherContributorOfBooks = new List<Book>();
}
}
The usage is then quite simple:
using (var dc = new MyDbContext())
{
// create sample data
var book1 = new Book() { Name = "Book 1" };
dc.Books.Add(book1);
var contrib1 = new Contributor() { Name = "Contributor 1" };
var contrib2 = new Contributor() { Name = "Contributor 2" };
var contrib3 = new Contributor() { Name = "Contributor 3" };
dc.Contributors.Add(contrib1);
dc.Contributors.Add(contrib2);
dc.Contributors.Add(contrib3);
dc.SaveChanges();
// add relationships
book1.Writers.Add(contrib1);
book1.Artists.Add(contrib1);
book1.Artists.Add(contrib2);
book1.OtherContributors.Add(contrib3);
dc.SaveChanges();
}
// verify that the contributor 1 has both Artist and Writer relations
using (var dc = new MyDbContext())
{
var contrib1 = dc.Contributors.Single(c => c.Name == "Contributor 1");
var hasWriter = contrib1.WriterOfBooks.Count == 1;
var hasArtist = contrib1.ArtistOfBooks.Count == 1;
if (!hasWriter || !hasArtist)
{
throw new Exception("Houston, we have a problem.");
}
}
I'm working on books at test.polarcomputer.com
If you have a book object and this object has writer,publisher,designer ..whoever, you need just 3 object :
1.book object
2.contributor object.
3.integration object
book object has
- bookid
- bookname
contributor object has
- contributorid
- name
- typeofcontributor // 0-writer 1-colorist 2-CoverArtists 3-whoever
integration object has
- bookid
- contributorid
- typeofcontributor // 0-writer 1-colorist 2-CoverArtists 3-whoever
Check this if i understant it truly , i can give you full solution.
The data model you show is OK, but one thing is clear. You can't map this as a pure many-to-many association. That's only possible if the junction table BookContributors only contains BookId and ContributorId.
So you always need an explicit BookContributor class, and getting a collection of one of the contributor types is always going to take this basic shape:
book.BookContributors
.Where(bc => bc.Type == type)
.Select(bc => bc.Contributor)
Clunky, compared to what you have in mind. But no way to get around it, I'm afraid. What's left is a few options in the implementation details.
Option 1: Get all contributors, filter later.
First, let's get the basic model right:
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public virtual ICollection<BookContributor> BookContributors { get; set; }
}
public class Contributor
{
public int ContributorId { get; set; }
public string Name { get; set; }
public virtual ICollection<BookContributor> BookContributors { get; set; }
}
public class BookContributor
{
public int BookId { get; set; }
public virtual Book Book { get; set; }
public int ContributorId { get; set; }
public virtual Contributor Contributor { get; set; }
public string Type { get; set; }
}
And the mapping:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Book>().HasMany(b => b.BookContributors)
.WithRequired(bc => bc.Book)
.HasForeignKey(bc => bc.BookId);
modelBuilder.Entity<Contributor>().HasMany(c => c.BookContributors)
.WithRequired(bc => bc.Contributor)
.HasForeignKey(bc => bc.ContributorId);
modelBuilder.Entity<BookContributor>()
.HasKey(bc => new {bc.BookId, bc.ContributorId, bc.Type});
}
(by the way, here I avoid the term 'Discriminator' because that suggests TPH inheritance, which isn't applicable - yet).
Now you could add properties to Book like these:
[NotMapped]
public IEnumerable<Contributor> Writers
{
get
{
return BookContributors.Where(bc => bc.Type == "writer")
.Select(bc => bc.Contributor);
}
}
The downside of this approach is that you always have to ensure that books are loaded with their BookContributors and their Contributors included, or that lazy loading is possible. And you can't use these properties directly in a LINQ query. Also, it's somewhat hard to get books and only their unique contributors (i.e. distinct).
Option 2: Inheritance - essentially the same
You could make BookContributor an abstract base class having a number of inheritors:
public abstract class BookContributor
{
public int Id { get; set; }
public int BookId { get; set; }
public virtual Book Book { get; set; }
public int ContributorId { get; set; }
public virtual Contributor Contributor { get; set; }
}
public class Artist : BookContributor
{ }
public class Writer : BookContributor
{ }
BookContributor now needs a surrogate key, Id, because EF will now use a field Discriminator, which is hidden, so it can't be configured as part of the primary key.
Now Book could have properties like...
[NotMapped]
public ICollection<Artist> Artists
{
get { return BookContributors.OfType<Artist>().ToList(); }
}
...but these will still have the same downsides as mentioned above. The only possible advantage is that you can use types now (with compile-time checking) in stead of strings (or enum values) to get to the various BookContributor types.
option 3: A different model
Maybe the most promising approach is a slightly different model: books and contributors, where each association between them can have a collection of contributor types. BookContributor now looks like this:
public class BookContributor
{
public int BookId { get; set; }
public virtual Book Book { get; set; }
public int ContributorId { get; set; }
public virtual Contributor Contributor { get; set; }
public virtual ICollection<BookContributorType> BookContributorTypes { get; set; }
}
And a new type:
public class BookContributorType
{
public int ID { get; set; }
public int BookId { get; set; }
public int ContributorId { get; set; }
public string Type { get; set; }
}
Modified mapping:
modelBuilder.Entity<BookContributor>().HasKey(bc => new { bc.BookId, bc.ContributorId });
Additional mapping:
modelBuilder.Entity<BookContributor>().HasMany(bc => bc.BookContributorTypes).WithRequired();
modelBuilder.Entity<BookContributorType>().HasKey(bct => bct.ID);
With this model you can either just get books and their distinct contributors, if you're not interested in the contributor's types...
context.Books.Include(b => b.BookContributors
.Select(bc => bc.Contributor))
...or with the types...
context.Books.Include(b => b.BookContributors
.Select(bc => bc.Contributor))
.Include(b => b.BookContributors
.Select(bc => bc.BookContributorTypes));
...or books with only writers...
context.Books.Select(b => new
{
Book = b,
Writers = b.BookContributors
.Where(bc => bc.BookContributorTypes
.Any(bct => bct.Type == "artist"))
})
Again, the latter query can be wrapped in a property...
[NotMapped]
public ICollection<Artist> Artists
{
get
{
return BookContributors
.Where(bc => bc.BookContributorTypes
.Any(bct => bct.Type == "artist"))
.Select(bc => bc.Contributor).ToList();
}
}
...however, with all aforementioned cautions.
Your model should be like that :
[Table("tblBooks")]
public class BookTbl
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int BookID { get; set; }
public string BookName { get; set; }
}
[Table("tblContributor")]
public class ContributorTbl
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ContID { get; set; }
public string Contributor { get; set; }
}
[Table("tblIntegration")]
public class IntegrationTbl
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int IntID { get; set; }
public int BookID { get; set; }
[ForeignKey("BookID")]
public BookTbl Book { get; set; }
public int ContID { get; set; }
[ForeignKey("ContID")]
public IntegrationTbl Integration { get; set; }
}

Join tables and get data from both of them

I have been trying to get data from the table I have joined to the main user table, the second table is to hold images. My current code posted below, only return the ImageID from the table when I want to be retrieving the ImagePath field, just to note this is a separate table as the user can add many images.
These are the models:
[Table("accountInfo")] // Table name
public class accountInfo
{
[Key]
public int AccountID { get; set; }
public int UserId { get; set; }
public int UserIdent { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public virtual ICollection<UserImages > UserImages { get; set; }
}
[Table("UserImages")] // Table name
public class UserImages
{
[Key]
public int ImageID { get; set; }
public int AccountID { get; set; }
public string ImagePath { get; set; }
public string ImageDesc { get; set; }
public int ProfileImage { get; set; }
}
Controller:
public ActionResult Index()
{
int id = (int)WebSecurity.CurrentUserId;
var users = db.AccountInformation.Include(c => c.UserImages).Where(c => c.UserId == id);
return View(users.ToList());
}
I am assuming I have gone wrong in the models set up. Can anyone help?
var a = db.AccountInformation.Include(c => c.UserImages.Select(x => x.AccountId)).Where(c => c.UserId == id);

ASP.NET MVC 4 Code First Many to Many Adding to Collection

I am using ASP.NET MVC 4 code first pattern for database layer. I have a many to many relationship between UserProfile and Task. When I try to add a task to the the collection of tasks of a user, it's added but if I try to query it and see if it's there it's not showing up.
My model:
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string SirName { get; set; }
public string Position { get; set; }
public string Email { get; set; }
public ICollection<TaskModels> Tasks {get; set; }
public bool? isActive { get; set; }
public UserProfile()
{
Tasks = new HashSet<TaskModels>();
}
}
public class TaskModels
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public ICollection<UserProfile> Employees { get; set; }
public int TimeNeeded { get; set; }
public int TimeWorked { get; set; }
public string Status { get; set; }
public bool isActive { get; set; }
public TaskModels()
{
Employees = new HashSet<UserProfile>();
}
}
public class WorkLogModels
{
public int Id { get; set; }
public UserProfile Author { get; set; }
public DateTime TimeBeganWorking { get; set; }
public int TimeWorkedOn { get; set; }
public TaskModels Task { get; set; }
public string Description { get; set; }
}
public class TimeTrackerDb : DbContext
{
public TimeTrackerDb() : base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<TaskModels> Tasks { get; set; }
public DbSet<WorkLogModels> WorkLogs { get; set; }
}
I try to check if a UserProfile already exists in a Task's Employees list and it's always empty.
[HttpPost]
public ActionResult Create(WorkLogModels worklogmodels)
{
var tasks = db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).SingleOrDefault();
if (tasks == null)
{
return View(worklogmodels);
}
if (ModelState.IsValid)
{
var user = db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).FirstOrDefault();
var task = db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).FirstOrDefault();
WorkLogModels log = new WorkLogModels();
log.Description = worklogmodels.Description;
log.TimeBeganWorking = worklogmodels.TimeBeganWorking;
log.TimeWorkedOn = worklogmodels.TimeWorkedOn;
log.Author = user;
log.Task = task;
db.WorkLogs.Add(log);
if (!db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).First().Tasks.Any(x=> x.Name == worklogmodels.Task.Name))
{
db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).FirstOrDefault().Tasks.Add(task);
db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).FirstOrDefault().Employees.Add(user);
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(worklogmodels);
}
I've been fighting with this for two days now.
Any help will be greatly appreciated
EDIT:
I am not sure if I made myself clear. In the Crate action for the WorkLog Controller I am trying to put the current user in the current task's collection and vice versa. It works correctly the first time, but then if I do it again it fails to skip the if statement and tries to add it once again and throws an exception : System.Data.SqlClient.SqlException. It's trying to add the same record to the intermediate table.

Resources