Reputation: 353
I'm new to the EF. To keep it simpler, let's say until recently, I had a table like so
CREATE TABLE customer
(
CustomerNumber int,
CustomerName nvarchar(100)
)
I had a class to handle this
[Table("customer")]
public class Customer
{
[Key]
public int CustomerNumber { get; set; }
public string CustomerName { get; set; }
}
With context:
public class MyContext : DbContext
{
public MyContext()
: base("name=MyContext")
{
}
public DbSet<Customer> Customers { get; set; }
}
With controller:
public class CustomersController : ODataController
{
MyContext db = new MyContext();
private bool CustomerExists(string key)
{
return db.Customers.Any(p => p.CustomerNumber == key);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
[EnableQuery(PageSize =20)]
public IQueryable<Customer> Get()
{
db.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
return db.Customers;
}
[EnableQuery]
public SingleResult<Customer> Get([FromODataUri] string key)
{
IQueryable<Customer> result = db.Customers.Where(p => p.CustomerNumber == key);
return SingleResult.Create(result);
}
}
Now recently I have a new table with new data to display
CREATE TABLE customerDetails
(
CustomerNumber int,
Role nvarchar(20),
ContactName nvarchar(30)
)
For each customer number, there are 2 entries in customerDetails table, differing on role, let's say A
and B
.
What I'm tryin to do is to get the result of the following query into my modified entity
Query:
SELECT c.CustomerNumber, c.CustomerName, cc1.ContactName as A_Name, cc2.ContactName as B_Name
FROM customer as c
JOIN customerDetails as cc1 ON c.CustomerNumber = cc1.CustomerNumber AND cc1.Role = 'A'
JOIN customerDetails as cc2 ON c.CustomerNumber = cc2.CustomerNumber AND cc2.Role = 'B'
I modified my entity:
[Table("customer")]
public class Customer
{
[Key]
public int CustomerNumber { get; set; }
public string CustomerName { get; set; }
public string A_Name { get; set; }
public string B_Name { get; set; }
}
Added:
[Table("customerDetails")]
public class Customer
{
[Key]
public int CustomerNumber { get; set; }
public string Role { get; set; }
public string ContactName { get; set; }
}
And modified the controller:
[EnableQuery(PageSize =20)]
public IQueryable<Customer> Get()
{
db.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
return from c in db.Customers
join cc1 in db.CustomerContacts.Where(e => e.Role == "A") on c.CustomerNumber equals cc1.CustomerNumber
join cc2 in db.CustomerContacts.Where(e => e.Role == "B") on c.CustomerNumber equals cc2.CustomerNumber
select c;
}
But it returns an empty set. How can I properly write that select statement here and populate my modified Customer
entity?
Upvotes: 0
Views: 46
Reputation: 34683
Your entities should reflect your overall table structure. Given a Customer entity with a CustomerDetails entity and a 1-many relationship between the two on CustomerNumber I would target the entities as:
public class Customer
{
public int CustomerNumber {get; set;}
public virtual ICollection<CustomerDetails> CustomerDetails {get; set;}
}
public class CustomerDetails
{
public int CustomerDetailId {get; set;}
public string Role {get; set;}
public int CustomerNumber {get; set;}
}
... and map the customer and customer details. Note the CustomerDetails would have it's own PK column, not CustomerNumber since for a single customer you'd have potentially 2x customer details (role A and role B)
I'd advise against passing entities to your view, instead, create a view model for the view to consume and select the relevant details from your entities using .Select
. This is best for performance, allows you to format/flatten the data to suit your view, and is much more secure than exposing your entire entity graph to a consumer.
Alternatively, if you want a specific set of related roles (optional) for a customer, then the customer table should have a RoleACustomerDetailsId and RoleBCustomerDetailsId as int?
which can then reference these related entities.
Upvotes: 1