I have an old system with a lot of stored procedures that I am redeveloping using C# and MVC. I created Entities base on the system and I use Entity Framework as ORM. What is the best practice to map output of an stored procedure that includes some joins to my entities.
For example I have table1, table2 and table3 then I have and stored procedure includes:
Select * from table1 join table2 on ...
join table3 on ..
then I want the entities be filled by this data and in my controllers I use linq for accessing this data
As I have this three table I created three entities:
class table1{
public int table1Id;
public String value{get;set;}
public IEnumarable<table2> table2List{get;set;}
}
class table2{
public int table2Id{get;set;}
public String table2value{get;set;}
public IEnumarable<table3> table3List{get;set;}
}
I just added some pseudo code to make it clear. I want to map output of stored procedure to these entities.
Related
My stored procedure returns a joined table like:
Employee Department
-------------------
John IT
Bob IT
Rob IT
Jane Sales
Mary Sales
I have the appropriate entities generated by EF:
class Employee
{
public int Id {get;set;}
public string Name{get;set;}
public int DepartmentId{get;set;}
public Department Deparment{get;set;}
}
class Department
{
public int Id {get;set;}
public string Name{get;set;}
public ICollection<Employees> Employees{get;set;}
}
I execute the stored procedure like this:
Database.SqlQuery<Department>("exec spGetDepartments").ToList();
And the result is a list of departments:
IT
IT
IT
Sales
Sales
Each has empty list of employees.
Can I have the 2 department entities with lists of corresponding employees?
The example is simplified, but the business requirement is use stored procedure as there is a complicated logic which is hard to replicate in LINQ.
You cannot employ the navigation properties on stored procedures.
Note the stored procedure doesn't actually employ a context method call, but an actual query execution.
You have to use the DBcontext, to accomplish the task you require.
Stored procedures aren't "composable".
The "Lazy loading" or its variants are only available via a context.
You could in theory achieve a read statement in a generic repository pattern, if you absolutely wanted to. It might even be efficient under some circumstances.
But in that case, your resultset on the stored procedure, would always have to hold your entire row set.
The behavior would be quite complicated. I wouldn't actually advise it. It might be possible, but smart? decidedly not.
In sql server, I have Students and Departments tables.
I want to get Student records from Student table; with their Department data from Departments table(so i joined them) and show them in an asp.net page.
In asp.net I created a Student class type to use in list in asp.net codebehind.
The list, takes Student class type data like this:
List<Student> lst = new List<Student>();
But I need to get Students with their Department datas. So I created a custom class in asp.net side called StudentsAndDepartments.
Now the list takes this class:
List<StudentsAndDepartments> lst = new List<StudentsAndDepartments>();
My question; do I have to create, for every query I make, an another new custom class?
If I create a custom class for every query I use, there are being too many classes inside the solution.
I think I'm doing wrong..
What should I do?
Thanks for helping..
You do not create a "StudentsAndDepartments" class.
What you are doing here is trying to "flatten out" the domain model, and use one class to represent something that is better defined as a relationship.
You create your domain model. And relate them.
public class Student
{
public string LastName
/* the above is an example 'scalar' property on the Student. you'll have others like FirstName, StudentIdenficationNumber, etc, etc. */
/* below is the 'relationshiop' property, use one of the two below but not both */
public ICollection<Department> Departments;
/* or */
public Department ParentDepartment;
}
public class Department
{
public string DepartmentName
public ICollection<Student> Students;
}
Then you "hydrate" the domain model.
Now this is where things can really vary.
Entity Framework with POCO can do this.
ADO.NET can do this. You write "Serializers" which convert IDataReaders into your object model. This is manual-mapping.
With ADO.NET, you may write different stored procedures...
dbo.uspStudentsGetAllWithParentDepartments
dbo.uspDepartmentsGetAllSimple
dbo.uspDepartmentsGetAllWithChildrenStudents
something like that.
Now, where I digress from others usually.
I do NOT write JOIN SQL statements.
I write 2 separate SQL statements (in ONE stored procedures) to get my data.
dbo.uspStudentsGetAllWithParentDepartments
would like like this
Select st.EmpKey, st.LastName, st.FirstName from dbo.Student st
Select dept.DepartmentKey, dept.DepartmentName from dbo.Department dept where exists (Select null from dbo.Student innerStud where innerStud.ParentDepartmentKey = dept.DepartmentKey )
Now, Entity Framework can do this sql-writing for you, but it is a start-up cost if you've never seen it before.
What my Microsoft-only friends won't mention is that EF does not support the .Merge() function like NHibernate does (another ORM tool). Which is a deal breaker to me. But that's a deeper discussion.
Define your domain-objects, their relationships, and then ask questions about "what's the best way to hydrate my domain-model based on my current skill-sets" (or without the skillset part if you're open to new ways)
Here is a link to another answer I posted...which is the serializer code for the ado.net way of hydrating your objects.
Why is DataTable faster than DataReader
I am using entity framework, code first, 4.0, hitting an existing legacy database for read-only access. The database is normalized, so
Table [Event]
[ID]
[Date_Entered]
[Event_Status_Key]
Table [Event_Status]
[Event_Status_Key]
[Event_Status_Description]
My class looks like
public class Event
{
public DateTime DateEntered { get; set; }
public string StatusDescription { get; set; }
}
This is a WCF service layer application.
My two questions:
Is there any easy way to populate the status description without creating a second Dictionary-type object? I've seen questions like this: Entity Framework Mapping to Lookup table, but they seem to be focused on object to object, and I really just want a primitive. I'd prefer using the fluent API as opposed to attributes.
When the data is loaded, is any of the data cached at the code layer? Or does each check on the StatusDescription mean a separate call on the [Event_Status] table?
Edit: A possible (more subjective, which is why I didn't bring it up) third question is how close should the data entities match the database. Is it always a one-to-one field/table? Is what I'm doing (joining two tables into one data entity obejct) bad?
Thanks.
Entity framework expects that you will map both tables as separate entities and use projection in your query:
var query = from e in context.Events
select new WcfEvent // Your original Event class is just DTO
{
DateEntered = e.DateEntered,
StatusDescription = e.EventStatus.EventStatusDescription
};
This example expects correctly one-to-one mapping of your Event and Event_Status tables.
If you need any kind of caching you will have to implement it yourselves. Projected results are not even tracked by the context.
I'm creating an ASP.NET MVC3 project in C# that is using an already existing SQL Server database.
The SQL Server has different databases, one for each customer. Each customer database has numerous tables, but I'm interested in only one table.
So, I'm interested in retrieving (and not updating or deleting) data from the same table of every customer.
This is the database configuration example:
DatabaseCustomerName1
- TableNeeded
DatabaseCustomerName2
- TableNeeded
DatabaseCustomerNameN
- Tableneeded
The question is... how do I create the model?
Knowing that If I had to do it for just one customer I would create the model basing on the fields of the tables, how can I manage the situation of having multiple customers?
Thanks in advance.
Attila
You should have an interface for Repository class
for example and different implementations for each custumer data base
internal interface IProductRepository
{
IEnumerable<Product> GetAll();
}
class ProductRepositoryCustumerOne : IProductRepository
{
public IEnumerable<Product> GetAll()
{
//code to retrieve data
}
}
class ProductRepositoryCustumerTwo : IProductRepository
{
public IEnumerable<Product> GetAll()
{
//code to retrieve data
}
}
after you can inject with IoC container what implementation you need
Let me just clarify your question, are you saying you've got
a number of customers with a database each?
So...
Databases
Customer A
Customer B
And for each of those customers you're saying you have a table that you want to access so you have
Customer A > TheTable
Customer B > TheTable
So you're asking, how can you create a Model that will work for any customer to access TheTable?
Is that correct?
What about creating a Sql View over all tables based on a select link this:
Select 'Customer 1' as Customer, c.* from FirstDb.dbo.Cusotmers c
Union Select 'Customer 2' as Customer, c.* from SecondDb.dbo.Cusotmers c
Union ...
Than you can handel this view with e.g. EF or linq to sql.
Is it safe to assume you are using Entity Framework? Is the schema in all the databases the same?
You should be able to create your model against one of the databases. Then whenever you want to select a different customer you will need to change the Initial Catalog (or equivalent) value in the connection string before you create your data context.
I don't have any code handy at the moment. Does this help?
I have two tables like this:
Table1(id, name)
Table2(id_of_table_1, code)
I don't need an entity for Table1 or Table2, but one entity for both together:
class Merge{
public virtual long id{get;set;}
public virtual string name{get;set;}
public virtual string code{get;set;}
}
How can I load the tables to the edmx so that they will considered as one?
I don't have any control on the database and I can't create tables or views.
You are looking for advanced mapping called Entity splitting.
I think this is what you're lookig for: How to: Define a Model with a Single Entity Mapped to Two Tables
In short, you need to do this:
Add the two tables as two separate entities to your model
Cut the scalar values from the Table2 entity to the Table1 entity
Delete the Table2 entity
In the Table Mapping options of the Table1 entity, map the Table2-fields to Table2
For a more detailed explanation, you can have a look at this blog post.
Create a function inside your Merge class that writes the properties of your class to the appropriate Table1 and Table2 EDMX objects. Your Merger class should have references to those EDMX objects as internal variables. So this class is like a wrapper for your 2 table objects.