Entity Framework Query Join issue - asp.net

I'm using an AJAX query to call a function that references a model.
So far it returns details to a user table, which all works fine. The problem is, I have a one to many relationship to another table.
Person - PersonId goes to joining table - personId linked to potentially multiple colourIds - colourId links to colour table.
So three tables - person, favourite colour and colour are involved.
I want to include a join in my original query but I'm having difficulty. The query:
TechTestEntities testTechObj = new TechTestEntities();
var Result = from p in testTechObj.People
join fp in testTechObj.FavouriteColours on p.PersonId equals fp.PersonId
join c in testTechObj.Colours on fp.ColourId equals c.ColourId
select p;
When I run this I get the error that 'The entity type FavouriteColours is not part of the model for the current context.'
I have also added FavouriteColours to the model like so:
public virtual DbSet<FavouriteColours> FavouriteColours { get; set; }
All the tables should be included in the ADO model, so I'm not sure what the problem is and how to retrieve the colour names through a join.
Edit:
Model code
namespace techTest4
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using techTest4.Models;
public partial class TechTestEntities : DbContext
{
public TechTestEntities()
: base("name=TechTestEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Colour> Colours { get; set; }
public virtual DbSet<Person> People { get; set; }
//public virtual DbSet<FavouriteColours> FavouriteColours { get; set; }
}
}

I had to guess what your classes look like, but take a look at this code:
( https://dotnetfiddle.net/TVqzse )
This snippet is the most interesting for you:
var favoriteColours = people.SelectMany(p => p.FavouriteColours);
foreach(var favoriteColour in favoriteColours) {
System.Console.WriteLine(favoriteColour.Color.ColorName);
}
This uses LINQ to extract the favourite colours of all people, and you should be able to do exactly the same in Entity Framework.

Related

EF Core custom results from stored procedure

I'm using EF Core which I believe is also known as EF 7? Anyways, I have a stored procedure that returns custom results that will not identify with any specific table. How am I supposed to access those results and how should I call the sql command?
Normally we have to use .FromSql but that is only available on entities, eg. _context.User.FromSql(). I don't have an entity for it.
So I tried building a dbset/entity for the results, but again, there is no associated table, and there is also no "Key". How am I supposed to parse the data then of the custom results?
You can create a fake entity for the result of your stored procedure. You can set any property as the Key, even if in the results of the stored procedure the key values are not unique.
For example if you have a table like the following :
CREATE TABLE [dbo].[banana_hoard]
(
[id] INT NOT NULL PRIMARY KEY IDENTITY (1,1),
[owner] NVARCHAR(64) NOT NULL,
[bananas] BIGINT NOT NULL
)
You can have a query that does not return the row id like this :
public class Program
{
public static void Main(string[] args)
{
using (var db = new MonkeyDbContext())
{
var sp_results = db.search.FromSql(#"execute <YOUR_STORED_PROC>");
str_result = String.Join("\n", sp_results.Select(a => JsonConvert.SerializeObject(a) ));
Console.WriteLine("stored proc result :\n" + str_result);
}
}
}
public class MonkeyDbContext : DbContext
{
public DbSet<StoredProcRow> search { get; set; }
protected override void OnConfiguring (DbContextOptionsBuilder builder)
{
builder.UseSqlServer(#"Server=(localdb)\monkey_db;Database=monkey_db;Trusted_Connection=True;");
}
}
public class StoredProcRow
{
[Key]
public string Owner { get; set; }
public long Bananas { get; set; }
}

How do I populate my model from a database entry?

I have set up a large form with lots of entries. It populates my model and then saves to the database. I also need to be able to pull this information out of the database, put it into the model, and populate a bunch of fields with it for review. How do I do this?
Using ASP.NET MVC 4 Razor.
var db = new TechProjPlansContext();
TechProjPlan model = new TechProjPlan();
I can set up my data context and model, but where do I go from here to populate the model with a data entry chosen by ID?
You can search by givenId and if found return result type of TechProjPlan otherwise null
var resultFound = db.TechProjPlans.Where(e=>e.Id = givenId).FirstOrDefault();
I strongly recommend following this tutorial step by step. From the tutorial to answer your question:
Write a Model class like:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
}
Add a DbSet to your Context class: (TechProjPlansContext in your project)
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
Make sure you can connect to the database server, check your connectionStrings in your Web.config file.
As you wanted to filter only one Entity by using ID, you need a Controller class:
public ActionResult Details(int id = 0) // here id is set to 0 if it's null
{
Movie movie = db.Movies.Find(id);
if (movie == null)
{
return HttpNotFound();
}
return View(movie);
}
As you see, you'll be returning View(movie), that means you return Details page with the Entity (a movie) you got from the database. And have a View, that renders to actual HTML code the client will see. At the top of it, add the line:
#model MvcMovie.Models.Movie // (something TechProjPlans.Models.Movie in your project)
#Html.LabelFor(model => model.Title)
This will create a simple text showing the movie's title.
It's not logical to go deeper within an answer, so rest is up to you with that tutorial. Just keep in mind that the code above is only one example and you can use endless variations within each level for your situation.
You can right click on the directory Controllers, select Add New and select your Model class and Context class at the page. That will produce a Controller and Views (index, edit, delete, details, insert) tied to it which will be a good way to start your MVC study.

How do I name a many-many table for EF6 and do I need to add special mapping for this?

I am using EF 6 and trying to map a many to many relationship. So far I have:
public partial class ObjectiveDetail
{
public ObjectiveDetail()
{
this.SubTopics = new List<SubTopic>();
}
public int ObjectiveDetailId { get; set; }
public string Text { get; set; }
public virtual ICollection<SubTopic> SubTopics { get; set; }
}
public partial class SubTopic
{
public SubTopic()
{
this.ObjectiveDetails = new List<ObjectiveDetail>();
}
public int SubTopicId { get; set; }
public int Number { get; set; }
public string Name { get; set; }
public virtual ICollection<ObjectiveDetail> ObjectiveDetails { get; set; }
}
Our DBA is going to write the code for the many to many table. Should this be as follows
with a table name of ObjectiveDetailSubTopic or something completely different ?
CREATE TABLE [dbo].[ObjectiveDetailSubTopic] (
[ObjectiveDetailId] INT NOT NULL,
[SubTopicId] INT NOT NULL
);
Can someone tell me if this is the correct way to create the table. Also do I have to
add some code to map the ObjectiveDetail and SubTopic classes to the new join class so
EF will know what to do?
Our DBA is going to write the code for the many to many table. Should
this be as follows with a table name of ObjectiveDetailSubTopic or
something completely different ?
As long as you follow the SQL Database table naming conventions, the table name can be anything. I usually name the join table like yours, by connecting the two table names.
To create the join table using sql, see below:
CREATE TABLE [dbo].[ObjectiveDetailSubTopic](
ObjectiveDetailSubTopicId int identity primary key,
ObjectiveDetailId INT NOT NULL,
SubTopicId INT NOT NULL,
foreign key(ObjectiveDetailId) references ObjectiveDetail(ObjectiveDetailId ),
foreign key(SubTopicId) references SubTopic(SubTopicId )
);
But you don't need to create the join table by your own, Entity Framework will create it for you. You just need to mapping the relationship with the Fluent API in your DbContext class like below:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ObjectiveDetail>().
HasMany(c => c.SubTopics).
WithMany(p => p.ObjectiveDetails).
Map(m =>
{
m.MapLeftKey("ObjectiveDetailId ");
m.MapRightKey("SubTopicId ");
m.ToTable("ObjectiveDetailSubTopic");
});
}

What's Automapper for?

What’s Automapper for?
How will it help me with my domain and controller layers (asp.net mvc)?
Maybe an example will help here...
Let's say you have a nicely-normalized database schema like this:
Orders (OrderID, CustomerID, OrderDate)
Customers (CustomerID, Name)
OrderDetails (OrderDetID, OrderID, ProductID, Qty)
Products (ProductID, ProductName, UnitPrice)
And let's say you're using a nice O/R mapper that hands you back a well-organized domain model:
OrderDetail
+--ID
+--Order
|--+--Date
|--+--Customer
|-----+--ID
|-----+--Name
+--Product
|--+--ID
|--+--Name
|--+--UnitPrice
+--Qty
Now you're given a requirement to display everything that's been ordered in the last month. You want to bind this to a flat grid, so you dutifully write a flat class to bind:
public class OrderDetailDto
{
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public int OrderCustomerID { get; set; }
public string OrderCustomerName { get; set; }
public int ProductID { get; set; }
public string ProductName { get; set; }
public Decimal ProductUnitPrice { get; set; }
public int Qty { get; set; }
public Decimal TotalPrice
{
get { return ProductUnitPrice * Qty; }
}
}
That was pretty painless so far, but what now? How do we turn a bunch of OrderDetails into a bunch of OrderDetailDtos for data binding?
You might put a constructor on OrderDto that takes an OrderDetail, and write a big mess of mapping code. Or you might have a static conversion class somewhere. Or, you could use AutoMapper, and write this instead:
Mapper.CreateMap<OrderDetail, OrderDetailDto>();
OrderDetailDto[] items =
Mapper.Map<OrderDetail[], OrderDetailDto[]>(orderDetails);
GridView1.DataSource = items;
There. We've just taken what would otherwise have been a disgusting mess of pointless mapping code and reduced it into three lines (really just two for the actual mapping).
Does that help explain the purpose?
If you have an object of one type and you want to populate the properties of an object of another type using properties from the first type, you have two choices:
Manually write code to do such a mapping.
Use a tool that will automatically handle this for you.
AutoMapper is an example of 2.
The most common use is to flatten models into a data transfer objects (or, in general, mapping across layer boundaries). What's very nice about AutoMapper is that for common scenarios you don't have to do any configuring (convention over configuration).
Map objects between layers. Good example: Here

Populating Models using LINQ

I'm trying to figure out a clear way of populating my model classes from LINQ to SQL generated objects. My goal is to keep my Models and LinqModels separate. Say I have the following models:
public class Person {
public List<Account> Accounts {get; set;}
}
public class Account {
public List<Purchase> Purchases {get; set;}
}
public Purchase {
public String Whatever {get; set;}
}
Now, I also have nearly identical data models generated by LINQ to SQL. So if I want to populate a Person object I'm going to add a getter method within the DataContext partial class:
public Person GetPersonByID(int personID) {
....
}
How we populate this Person object and its children properties throughout the rest of the application is done like this:
public Person GetPersonByID(int personID) {
Person res =
from p in Persons
select new Person() {
Accounts = (
from a in p.Accounts
select new Account() {
Purchases = (
from m in p.Purchases
select new Purchase() {
Whatever = m.Whatever
}
).ToList()
}
).ToList()
}
return res;
}
So for each child property we need to extend the query. What I would really prefer is if I could do something more like this:
public Person GetPersonByID(int personID) {
return new Person( this.Persons.SingleOrDefault( p => p.ID == personID ) );
}
....
public class Person {
public Person(DataModels.Person p) {
Accounts = (from a in p.Accounts select new Account(a)).ToList();
}
}
public class Account {
public Account(DataModels.Account a) {
Purchases = (from r in a.Purchases select new Purchase(r)).ToList();
}
}
public class Purchase {
public Purchase(DataModels.Purchase r) {
Whatever = r.Whatever
}
}
This is much more manageable, but the initial GetPersonByID call does not return the data I need to populate these child objects. Is there any way around this?
Or is there a better alternative to populating model objects using LINQ to SQL?
*** Sorry if my code examples are not quite right*
What you are looking for is called "persistence ignorance".
It is a valued property of a design, specifically in the DDD (Domain Driven Design) circles.
You can achieve it for example using LinqToSQL's XML mapping capabilities, where you do not generate data classes and indicate to LTS how to map your domain classes (Account, Purchase etc) to the database directly.
Because of LinqToSQL's limited capabilities in terms of mapping options (specifically the lack of value objects, the limitation on the inheritance mapping and the lack of Many-to-Many relationship support), it might or might not work in your case.
Another option, if you have your LTS-generated classes and your domain classes as above, is to look into Automapper, which can help getting some of the repetitive work out of the way.

Resources