C# Entity Framework Database First - use only some fields - c#

I am creating a site using EF database-first with ASP.NET MVC (I follow all of this tutorial: https://www.asp.net/mvc/overview/getting-started/database-first-development/creating-the-web-application) and everything is working ok.
The problem is that in the index view (the list of records) I want to remove one of the fields from the the entity. I don't just want it to be hidden in the views, but all together removed (the issue is that it holds a very big chunk of data, which make the loading of the list very slow).
On the "edit" view I do want to show and use all fields.
If I remove one field from the the entity, I get this error:
The entity type XXX is not part of the model for the current context.
on
return View(db.XXX.ToList());
What can I do?

There are a couple of ways you can go about this. The issue, at hand, is the .ToList().
If you just do db.XXX, then you will obtain an Enumerable, which, until it is enumerated, is just a set of instructions to grab data from the DB. Once you call .ToList() it will actually go and grab the data from the DB, which is the step that is taking so long.
The best thing to do, in my opinion is define a ViewModel that contains all of the fields except the one with the large amount of data.
public class ViewModel
{
public ViewModel(){}
public int Id {get;set;}
public string OtherData {get;set;}
}
Move the
db.XXX outside of the View function as so:
var initialDBObject = db.XXX;
From there you can take your Enumerable (which is still just a set of instructions to access data from your DB) and Select it into your ViewModel object like so:
var viewModelObject = initialDBObject.Select(x=> new ViewModel
{
Id = x.Id;
OtherData = x.OtherData;
//do not add the large column of data to the ViewModel
});
What is happening here (before calling ToList()) is you are modifying the query that linq generates behind the scenes to grab the data from table XXX (if you put a break-point on this line and hover over initialDBObject you will see the SQL that gets generated). Instead of just grabbing the data from table XXX, the query will grab the data and insert it into a ViewModel object (instead of the XXX object, as defined in your .edmx file) once you call ToList().
You can also
.Select(x=> new
{
Id,
OtherData
});
and create an anonymous object, but getting an anonymous object to work in a View is a little complicated.
Then you need to update the Index View page to use the ViewModel instead of the original DB object and you can pass it like:
View(viewModelObject.ToList());
Name the ViewModel something besides ViewModel, though. Like [DB Table Name]ViewModel or something similar.
If you have lots of rows in the DB it will still take a long time to load all of the data, in which case you need to look into Paging.
There is no problem with ToList(), on its own, the original issue was caused by the call to ToList() because it is at that point in the code that the program goes to the database and uses the linq-generated query to grab the data. If you are trying to ToList() an entire table's worth of data, or as in your case, have a column with a huge chunk of data, it may take some time or you may run out of memory.
Regarding the 15 columns that you have to include in the .Select(), yes, that is annoying. Unfortunately, you cannot use a constructor in a linq statement, so are forced to populate each column.
Another alternative to defining a ViewModel, which may be a little bit easier is to open up the .edmx design surface, right-click the background and Add New->Entity. You can use table XXX as a base, give it a different name, like XXXViewModel or whatever and then delete the column containing the large amount of data. Then you just need to do db.XXXViewModel.ToList().

Related

DbContext with read-only set properties

I was reading this article http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-2-connections-and-models.aspx and was trying to figure out how to create private setters (the section in the article DbContext with read-only set properties is right before the summary). How would you create private setters? I was playing around with different methods but nothing seemed to work. I am doing this because I need to group the original table based on a query I have because the original table is a heap and I need a primary key for the entity. So anytime a client asks for this table it is already grouped. Not even sure if this is the correct way to do that. Thanks.
EDIT: sorry for being vague. I am doing code first. For example there exists a SQL Table with JobNbr, Qty and Date and I need to group by JobNumber, sum on Qty and take the oldest expiration date, and that will be my entity since this table has no primary key. The way I am doing it now gives me the error below from a method I created in the DbContext class. I do have a EntityTypeConfiguration class. Do I do this in that class?
EDIT: : you might be wondering why I am doing this. Basically I need to get data from the heap and save it in another database. My original approach was database.SqlQuery() to get grouped rows from the heap, but sometimes I have too many parameters for execute_sql. So I decided to create an entity for the grouped query without tracking changes (since all I am doing is reading from the table and saving to another DB). See my post here with the issue I am having https://stackoverflow.com/questions/22106030/entity-framework-6-this-database-sqlquery-character-limitation-with-sp-executes. The only way I know to get around it is to create an entity (even though in this case the entity is a query and not a table).
The entity or complex type
' cannot be
constructed in a LINQ to Entities query.

How can I denormalize my clr entity, but keep my db tables normalized?

I have these two related tables Client (ClientId, Name) and ClientDescription (ClientDescriptionId, (FK) ClientId, Description). That is to say each Client can have many associated descriptions. Now, when displaying the a list of ClientDescriptions, I also need to know what the Name of it's associated Client is.
Now you'll probably say that I allready have this information, since I can simply follow my navigation property back to the associated Client and use its Name. I can't do that because I'm autogenerating a grid in Ria services, and this just gives me a count for navigation properties, and I haven't found a way to flatten this down in my metadata file. Hence why I want a property.
The whole idea is that I want to be able to add a new field to my database, update my entity classes from the database and regenerate my domain service, and the new field should just pop up in my grid. I shouldn't have to update my xaml just because my database happen to have an extra field.
So, what I would like to do is add a ClientName field to the entity (clr object), but keep my database clean (no such denormalization in the db).
So, I generated my edmx, and added a new property named ClientName. Set it to StoreGeneratedPattern.Computed, and compiled. I then get a nasty little error
Error 3004: Problem in mapping fragments starting at line NN: No mapping specified for properties (etc..)
The solution apparently is to generate my database from my edmx. (Or that's what answers to questions about that error seems to yield.) But this generates an actual DB-field, which I don't want, so that answer doesn't apply to my case.
So my question is: How can I denormalize my clr entity, but keep my db tables normalized?
Edit: I guess this question can be generalized a bit. The issue would be the same if ClientDescription contained a few numeric fields that I wanted to do some calculations on, and I wanted the result available as a field and the algorithm should be in c# rather than in my database.
To answer your more generalized question:
Entities are generated by the Entity Framework with a partial keyword.
This means that the code of an entity can be split in multiple source files in the same namespace and assembly. One will contain the generated code from the Entity Framework, the other will contain custom properties and methods.
If for example, your entity has the database fields Price and Amount you could add a property in the partial class TotalPrice which would return Price * Amount.
Then the algorithm will be C# and your database won't know about the extra property.

ASP.NET MVC3 update only necessary fields

Suppose we have class PersonModel, user edits a detail form in the browser and hits the submit button.
How to write a controller logic to create an UPDATE SqlComand (no EF) and update only those of fields from class PersonModel (FirstName, LastName, Age...) which have been changed.
What should be an argument of the /Person/Edit/<id> controller?
You don't do anything special to your MVC code, and you don't add any special URL parameters.
If you only want to update the changed fields, then you have to write a lot of code. You have to get the current record, compare each of your models fields to the records fields, figure out which ones have changed, then you have to construct a SQL statement based on the changed fields, then update it, making sure to use optomistic record locking to insure the field has not changed between when you retrieved it and when you update it.
This is probably going to be a couple hundred lines of code. Or it could be one line of code if you were using an ORM.
Also, keep in mind you need to use parameterized statements as well, to insure against a SQL injection attack (something you get for free in an ORM as well).
Good luck, I certainly am not going to write it.
What I would suggest is that you don't use the generalized PersonModel which I assume is a 1:1 representation of your data model. You should create a watered down view model of with only the fields you care about. Then use something like AutoMapper to map the ViewModel back to your DomainModel.
Here is a reference on how to use AutoMapper for such a scenario.
How to cross map objects using AutoMapper
You may use Linq and let the datacontext do everything for you.
In the Model you just create your data class with the linq queries for the update, retrieve the object, set all the values that have been passed from the view in the object you've retrieved (you'll have to do this anyway, since the pattern decouples the view from the model | Remember too, that MVC implements observer for letting the view to know about changes in the model, so you can't know what was modified in the view from the controller), and then you call the DataContext.SubmitChanges(); method. The data context will do the job in its own. It will know what to change and modify and will make the most performant query.

Entity Framework: subset entity of larger entity

Sooo basically I have a table called Comment. On that table I have three fields,
ID
Title
Text
I've created an Entity object for the table already and it maps all three fields, but what I want now is another Entity called CommentHeader that will map only ID and Title. I want to only load the titles of all the comments and not the text for speed reasons. So what's the best way for going about this?
I'm not looking for a Select statement with a var object. I can figure that one out on my own and I really don't like that solution because I'd much rather abstract it behind an Entity object.
I've tried the obvious solution, which was to just copy the original Entity object and delete Text from it. That resulted in an error because only one Entity can map to one table without conditions. It sounds to me like I have no choice but to use a Select statement. I just wanted to make sure before I did something stupid.
(By the way this example only has three fields for simplicity's sake. Assume that the header could have considerably more fields in it. This is the primary reason I don't want to just use a select with a var object, because it's not just one field but could be a whole bunch of fields).
The easiest way probably would be to create a view ("CommentHeaders") in the database that only selects ID and title from the Comment table. Then update your model and add the view, which will create a new entity based on those columns.

Mapping strongly-typed DataSets in a generic FillDataSet method in C#?

Edit: I am using SqlDataAdapters to fill the data sets. Sorry--I should have been more clear.
I'm working on a project where I need to fill a number of strongly-typed data sets with information from stored procedures. Right now, I have a generic method in my data access layer:
public static DataSet FillDataSet(DataSet dataSet, string storedProcedureName, Dictionary<string, string> parameters);
The problem with this is that I need to establish mappings between the returned recordsets from the stored procedure and the tables in my data sets. I have come up with two options for doing this:
Add a new formal to my FillDataSet method (KeyValuePair<string, string>[] mappings) that would provide the information for the table mappings.
Create a DataSetMappingFactory that would take a DataSet as a parameter and then add the appropriate mappings based on its type. If it were an unknown type, then it wouldn't add any mappings. Then, it would return the DataSet to the FillDataSet method.
Do any of you have other thoughts about how I could approach this problem? Also, does anyone want to weigh in on an approach that would be best in terms of object-oriented design?
The first question I'd ask is: do I really need to do this at all? The typed DataSet designer already gives you a tool for defining the mapping between a stored procedure and a DataTable. If you design your DataSet with care, you already have a Fill method for every DataTable. Does it make sense to reinvent that wheel?
I think it might. It's really cool that there's a way to maintain that mapping, but everything in that mapping is frozen at compile time. If you want to change the mapping, you need to rebuild your assembly. Also the typed DataSet design doesn't deal with stored procedures that return multiple result sets. If you want to generically map parameters and values, you have to use reflection to get the argument lists from the Fill methods. It may be that if you look at those factors (and others I'm not thinking of), working with the existing tool isn't the way to go.
In that case, it seems to me that your goal is to be able to populate a DataSet from a series of stored procedures with code that knows as little as possible about the implementation details. So this is a process that's going to be driven by metadata. When you have a process driven by metadata, what's going to matter the most to you in the long run is how easy it's going to be to maintain the metadata that the process uses. Once you get the code working, you probably won't touch it very much. But you'll be tweaking the metadata constantly.
If I look at the problem from that perspective, the first thing I think to do is design a typed DataSet to contain the metadata. This gives us a bunch of things that we'd otherwise have to figure out:
a persistence format
a straightforward path to building a bound UI
an equally straightforward path to persisting the metadata in a database if we decide to go down that road
an object model for navigating the data.
In this DataSet, you'd have a DataSetType table, keyed on the Type of each typed DataSet you intend to be able to populate. It would have a child StoredProcedures table, with a row for each SP that gets called. That would have two child tables, Parameter and DataTableType. There would be one DataTableType row, ordered by ordinal position, for each result set that the SP's expected to return. The DataTableType table would have a child ColumnMapping table. It's in that table that you'd maintain the mappings between the columns in the result set and the columns in the table you're populating.
Make sure all of your DataRelations are Nested, and that you've given rational names to the relations. (I like FK_childtablename_parenttablename.)
Once you have this, the class design becomes pretty straightforward. The class has a reference to the metadata DataSet, the Connection, etc.,, and it exposes a method with this signature:
public void FillDataSet(DataSet targetDs, Dictionary<string, Dictionary<string, KeyValuePair<string, string>> parameterMap);
You start by using the targetDs's Type to find the top-level DataSetType row. Then all of the private methods iterate through lists of DataRows returned by DataTable.GetChildRows(). And you add an event or two to the class design, so that as it performs the operation it can raise events to let the calling application know how it's progressing.
Probably the first place I'd expect to refactor this design is in giving me more fine-grained control over the filling process. For instance, as designed, there's only one set of SPs per typed DataSet. What if I only want to fill a subset of the DataSet? As designed, I can't. But you could easily make the primary key of the DataSetType table two-part, with the parts being DataSet type and some string key (with a name like SPSetName, or OperationName), and add the second part of the key to the FillDataSet argument list.

Categories