Should I use separate models for domain and EF? - c#

Scenario: I am writing a program that handles report generation.
I have the report stored in a database, mapped to an EF model. There are some non-database fields (i.e. some fields are auto-calculated based on other fields that ARE in the db). Would it make sense to have one class that solely maps to the DB, and another class that takes that information and additionally has the other calculating fields?
i.e. a sample class to interact with the codefirst database would be
public class Report{
public int CategoryOneSeverity {get; set;}
public int CategoryTwoSeverity {get;set;}
public string Title {get;set;}
}
Would it make sense to make another class, like:
public class ReportModel{
public int CategoryOneSeverity;
public int CategoryTwoSeverity;
public string Title;
public int RiskRating{
get{ return CategoryOneSeverity + CategoryTwoSeverity; }
}
}
Or should the RiskRating property be in the EF model.

Yes, I absolutely believe you should have different classes to model your domain than your DB. Unless your application is extremely trivial, if you try to map your domain objects directly, you invariably have to change them to match what you need your data structure to be, and possibly expose things you don't want to expose. Think of it as a violation of the Single Responsibility principle; your class has two reasons to change if you make it your domain object and map it directly. One is in response to changing business requirements, the other is in response to changing data storage schema.

"Would it make sense to have one class that solely maps to the DB, and
another class that takes that information and additionally has the
other calculating fields?"
Most likely yes. Usually I would create a new class suffixed with "ViewModel" such as HumanResourcesReportViewModel if my entity class was HumanResourcesReport.
There's lots of variations on how to use ViewModels, and we could get into a pedantic debate about terminology, but conceptually, take your entity and create a new class with that data plus whatever additional information you need to process the report. In this case the report generation is in a way the View of the MVC model, so I don't think it's offensive to call the class holding the data a ViewModel.

Are you using Code First or DB First?
You can have auto calculated fields in your model, which are not mapped to fields in the database.
It also depends on your architecture. If you're using DB first, refreshing your EF model would update your EF classes, losing your mapped fields. In the DB-First scenario, an alternative would be to use the EF model class as your base class and inherit from it for your report class.
public class ReportModel
{
public int CategoryOneSeverity;
public int CategoryTwoSeverity;
public string Title;
}
public class ReportClass : ReportModel
{
public int RiskRating
{
get { return CategoryOneSeverity + CategoryTwoSeverity; }
}
}

Related

C# Winforms data entry app with dirty/new tracking

I've developed a winforms app for data entry and I want to know if there is a better way to handle the dirty/new tracking and committing changes to the database (SQL Server).
My overall strategy is this:
I have several business objects and most of them have a corresponding data entry form.
I have implemented INotifyPropertyChanged on these business objects.
I also created an interface to handle Dirty tracking. It looks like this:
public interface IRecord
{
bool NewRecord {get;set;}
bool Dirty {get;set;}
int SaveRecord();
}
Each business object (e.g. Region) that has a corresponding data entry form gets a derived type:
public class Region
{
public string RegionName {get;set;}
public string List<Study> Studies {get;set;}
}
public class RegionRecord: Region, IRecord
{
public bool Dirty {get;set;}
public bool NewRecord {get;set;}
int ID { get;set; } // ID is here so it is not in the base class
public new List<StudyRecord> Studies {get;set;}
public int SaveRecord()
{
if (NewRecord)
// stored procedure insert, return 1 on error
else if (Dirty)
// stored procedure update, return 1 on error
return 0;
}
}
I did this to remove the "database" fields like ID from the basic business objects. I was trying to make a layer between the business object and and object that would interact with the database and I thought the ID wasn't necessary for the business class to have.
As defined above, some business objects have a property that is another List. In this case, a Region can have many Study objects. On the data entry form, I also want to track changes to each of these Study objects (usually via a DataGridView). You can see that I've hidden the base Studies property and replaced it with a List<StudyRecord> version.
Each data entry form uses a Binding Source with a BindingList (e.g. BindingList<RegionRecord>) as its data source. This way I can detect changes to the properties of these objects and then set the Dirty property of each object.
I also build reports with OpenXML wordprocessing and use the base objects to populate these reports. My issue is that the properties that are lists are empty because they are hidden. It feels wrong to keep both the base and derived version of the properties in sync.
I feel like I've painted myself into a corner with this implementation and there must be a better way.
Am I going about this all wrong?

Better practise to hide sensitive fields in EF model or create a new class?

I'm using code-first with entity framework for modeling and creating my db.
I'm just wondering - when I return objects to the user - I don't want to return data sensitive fields like id.
Should I add an atttibute like [DoNotReturn] combined with a filter to remove this fields when returning to the user, or should I just make a whole new class which doesn't contain these fields?
Example:
public class UserAccount
{
//Option 1 - Hide fields
[DoNotReturn]
public int Id { get; set; }
[Index(IsUnique = true)]
[MaxLength(50)]
public string Username { get; set; }
public decimal Cash { get; set; }
[DoNotReturn]
public Account Account { get; set; } //Contains Email / Password
//Option 2 - return a `safe` version
public User UserAccountToFriendly() {
return new FriendlyUser(this.Username, this.Cash);
}
}
Keep your database model separate from your view model that's the approach I have taken and doing it for a long time. it will give you a good separation. Once you start dealing with ViewModel then you can use a library like Automapper or custom mapping classes to convert ViewModel to database model or vice-versa. I hope it helps
Never use your database models as result for end-users and keep it separate from Presentation/Application layer.
There are so many problems that you will encounter:
disclosure of sensitive data (you've mentioned about);
performance issues and waste of RAM and CPU (for instance, you have Order entity with dozens of properties, it would be better to load only those properties that is required instead all);
problems with serialization (with enabled lazy-loading, for instance MVC could try to serialize whole object with navigation properties... );
etc...
I'd like to recommend the following:
return original database entity from Repository layer if necessary, but don't forget to cast it on Presentation layer to another completely brand new xxxModel, xxxViewModel, xxxResponse, etc;
return xxxView from Repository layer if you want to achieve best optimizations, but don't forget to cast it on Presentation layer to brand new object. (any changes on one layer shouldn't affect others, especially end-users);

OOP/Repository pattern: creating too many objects for different subsets of database access?

I'm porting old VB6 code (yes yes, VB6...) to C#. I'm refactoring code to be more object-oriented, and among other things, I'm implementing repository classes to access the database.
Now, these repository classes return objects, not datasets. But I find that sometimes I only return a subset of the information an object might hold. Example: I can get a complete list of documents, with name, filepath, folder, creator, etc - or I can get document search results which only contain name and folder.
What is the best practice for these subset cases? Should I create custom objects for these database calls, that only contain the subset of data? Should I return the complete objects with only some of their fields populated? Or should I just return datasets?
Ideally, everything should be centralized as much as possible. This could be done by creating a query object for each subset. I think you can go either way with returning objects with some fields populated or null, dependent if your database allows nulls for those specific fields.
So centralize your rules and logic with your repository classes so that each object is returned consistently based on those rules and logic.
Create an underling schema for your objects so they do not get too complex. I think what is need is an entity per object to be consider for repository. Again, creating custom objects or DTO's could create unneeded code and complexity. For the sake of integrity, keep your objects with some fields populated and others that are not needed within that subset null, that way if this information is queried later, information can be reported back that value does not exist for a specific entity.
Here is a brief example, try using POCO classes with the entity framework.
public interface IRepository<TEntity, in TKey> where TEntity : class
{
TEntity Get(TKey id);
}
public class SomeRepo1 : IRepository
{
private readonly FileDbContext someDbContext;
public FileRepository(FileDbContext dbContext)
{
someDbContext = dbContext;
}
public File Get(string id)
{
return someDbContext.Files.ToList();
}
}
Example of POCO Class that can be used for files:
public class File
{
public int Id { get; set; }
public string FileName { get; set; }
}
public class Folder
{
public List<File> Files { get; set; }
}
More details here: https://msdn.microsoft.com/en-us/library/ff649690.aspx
Hope this helps!
But I find that sometimes I only return a subset of the information an object might hold.
You have just confused the object model with the persistence model.
You see, the object model doesn't care how the storage is implemented. Specifically, if there is a database behind the object model and you have tables that contain some data, you are free to map the database to your object model in any way you want. With a clever object-relational mapper you can for example split a table into two classes or have multiple classes persisted in the same table.
So, something that looks like "a subset" from the perspective of your storage, could possibly not be "a subset" from the object-model perspective.
An example specific Entity Framework 6 solution involves so called Table Splitting which allows you to split a model class into two classes, a class with core properties that are always loaded and another class with auxiliary properties that are lazily loaded only when you refer to the virtual property of the core class.
An example tutorial: http://www.c-sharpcorner.com/UploadFile/ff2f08/table-splitting-in-entity-framework-6-code-first-approach/
(just to mention, the opposite, where two physical tables are mapped to oe model class is called Entity splitting)

How to expose calculated data of an entity through WCF

We’re developing an N-tier architecture application using WCF between client (presentation) and server (data/business layer). To be honest I can’t find any real examples/info of how to expose efficiently calculated data through WCF.
For describing my problem say we have ATM machines which have lots of transactions. So we have an 1-N relation between ATM Class and Transaction class. ATM Class has properties like Location, ModelNo, Description, InstallDate and the Transaction records have info like Amount, DateTime, CustomerInfo, TicketPaperLength, ElectricityUsed
Exposing these classes through WCF is not the issue. Problem is that we have lots of calculated fields for ATM that are based on the underlying Transaction table. For example, the client application uses reports based on the calculated data of ATM. Examples of calculated data of ATM could be: AverageTicketPaperLength, AverageAmount, DeviationAmount, AverageElectricity, etc, etc. There are lots and lots of these calculated data. The calculations should take place on the server and not on the client-side. If these report definitions were all fixed it wouldn’t be that big a problem: we could create separate services/Poco’s, for the reports. Put the calculations in a business layer and fill the Poco as needed. But the client application must have the ability to make reports filtered on whatever set of calculated properties of ATM and return as data another set of (calculated) properties.
I could create a Poco with about 500 calculated properties where there for each single report only may be 10 properties would be used. But of course we don’t want all 500 calculations executed every time for each and every entity.
So in general I’m wondering how one would expose calculated data of an entity through e.g. WCF. Almost all examples I see explaining Entity Framework, Poco and WCF only deal with the persistent fields of the entity and that is pretty straight-forward.
Do not expose entities through WCF, create some DTOs.
For example:
In wcf layer -
DtoInfoForReport1 GetInfoForReport1(long atmId) { ... call BL here... }
DtoInfoForReport2 GetInfoForReport2(long atmId) { ... call BL here... }
In data layer -
AtmEntity
{
long Id {get;set;}
... some properties ...
HashSet<Transaction> AtmTransactions {get;set;}
}
Transfer objects -
DtoInfoForReport1
{
long AtmId {get;set;}
XXX SomeCalculatedValue {get;set;}
}
In BL -
DtoInfoForReport1 CreateInfoForReport1(long atmId)
{
var atm = YYY.GetEntity<AtmEntity>(atmId);
return new DtoInfoForReport1
{
AtmId = atmId,
SomeCalculatedValue = DoSomeCalculationOverMyAtmWithItsTransactions(atm),
};
}
Hope I got your question right. Otherwise comment.
Edit based on comment:
Than I would suggest DTOs like this:
[DataContract]
public DtoRequestedCalculations
{
[DataMember]
public long AtmId {get;set;}
[DataMember]
public List<DtoRequestedCalculationEntry> Calculations {get;set;}
}
[DataContract]
public DtoRequestedCalculationEntry
{
[DataMember]
public string / long / Guid / XXX ParameterIdentifier {get;set;}
[DataMember]
public double/ DtoParameterCalculatedValueBase {get;set;}
}
Now if your calculated value is always double it's basically done. If your values may be or different types you will need some base class - DtoParameterCalculatedValueBase, which is sth like this:
[DataContract]
[KnownType(typeof(DtoParameterDoubleCalculatedValue))]
[KnownType(typeof(DtoParameterXXXCalculatedValue))]
public DtoParameterCalculatedValueBase
{
...whatever common part there may be or nth...
}
public DtoParameterDoubleCalculatedValue : DtoParameterCalculatedValueBase
{
[DataMember]
public double Value {get;set;}
}
public DtoParameterXXXCalculatedValue : DtoParameterCalculatedValueBase
{
[DataMember]
public XXX Value {get;set;}
}
Note the KnownType attribute - it tells WCF what types may come in place of base class. You will have to provide this attribute for each inherited type (or use DataContractResolver, which is already another story).
Than in WCF:
DtoRequestedCalculations GetCalculatedValuesForAtm(long atmId, List<long / string/ Guid / XXX> valueIdentifiers);

MVC ViewModels and Entity Framework queries

I am new to both MVC and Entity Framework and I have a question about the right/preferred way to do this.
I have sort of been following the Nerd Dinner MVC application for how I am writing this application. I have a page that has data from a few different places. It shows details that come from a few different tables and also has a dropdown list from a lookup table.
I created a ViewModel class that contains all of this information:
class DetailsViewModel {
public List<Foo> DropdownListData { get; set; }
// comes from table 1
public string Property1 { get; set; }
public string Property2 { get; set; }
public Bar SomeBarObject { get; set; } // comes from table 2
}
In the Nerd Dinner code, their examples is a little too simplistic. The DinnerFormViewModel takes in a single entity: Dinner. Based on the Dinner it creates a SelectList for the countries based on the dinners location.
Because of the simplicity, their data access code is also pretty simple. He has a simple DinnerRepository with a method called GetDinner(). In his action methods he can do simple things like:
Dinner dinner = new Dinner();
// return the view model
return View(new DinnerFormViewModel(dinner));
OR
Dinner dinner = repository.GetDinner(id);
return View(new DinnerFormViewModel(dinner));
My query is a lot more complex than this, pulling from multiple tables...creating an anonymous type:
var query = from a in ctx.Table1
where a.Id == id
select new { a.Property1, a.Property2, a.Foo, a.Bar };
My question is as follows:
What should my repository class look like? Should the repository class return the ViewModel itself? That doesn't seem like the right way to do things, since the ViewModel sort of implies it is being used in a view. Since my query is returning an anonymous object, how do I return that from my repository so I can construct the ViewModel in my controller actions?
While most of the answers are good, I think they are missing an in-between lines part of your question.
First of all, there is no 100% right way to go about it, and I wouldn't get too hung up on the details of the exact pattern to use yet. As your application gets more and more developped you will start seeing what's working and what's not, and figure out how to best change it to work for you and your application. I just got done completely changing the pattern of my Asp.Net MVC backend, mostly because a lot of advice I found wasn't working for what I was trying to do.
That being said, look at your layers by what they are supposed to do. The repository layer is solely meant for adding/removing/and editing data from your data source. It doesn't know how that data is going to be used, and frankly it doesn't care. Therefore, repositories should just return your EF entities.
The part of your question that other seem to be missing is that you need an additional layer in between your controllers and the repositories, usually called the service layer or business layer. This layer contains various classes (however you want to organize them) that get called by controllers. Each of these classes will call the repository to retrieve the desired data, and then convert them into the view models that your controllers will end up using.
This service/business layer is where your business logic goes (and if you think about it, converting an entity into a view model is business logic, as it's defining how your application is actually going to use that data). This means that you don't have to call specific conversion methods or anything. The idea is you tell your service/business layer what you want to do, and it gives you business entities (view models) back, with your controllers having no knowledge of the actual database structure or how the data was retrieved.
The service layer should be the only layer that calls repository classes as well.
You are correct a repository should not return a view model. As changes to your view will cause you to change your data layer.
Your repository should be an aggregate root. If your property1, property2, Foo, Bar are related in some way I would extract a new class to handle this.
public class FooBarDetails
{
public string Property1 {get;set;}
public string Property2 {get;set;}
public Foo Foo {get;set;}
public Bar Bar {get;set;}
}
var details = _repo.GetDetails(detailId);
If Foo and Bar are not related at all it might be an option to introduce a service to compose your FooBarDetails.
FooBarDetails details = _service.GetFooBar(id);
where GetFooBar(int) would look something like this:
_fooRepo.Get(id);
_barRepo.Get(id);
return new FooBarDetails{Foo = foo, Bar = bar, Property1 = "something", Property2 = "something else"};
This all is conjecture since the design of the repository really depends on your domain. Using generic terms makes it hard to develop potential relationships between your objects.
Updated
From the comment if we are dealing with an aggregate root of an Order. An order would have the OrderItem and also the customer that placed the order.
public class Order
{
public List<OrderItem> Items{get; private set;}
public Customer OrderedBy {get; private set;}
//Other stuff
}
public class Customer
{
public List<Orders> Orders{get;set;}
}
Your repo should return a fully hydrated order object.
var order = _rep.Get(orderId);
Since your order has all the information needed I would pass the order directly to the view model.
public class OrderDetailsViewModel
{
public Order Order {get;set;}
public OrderDetailsViewModel(Order order)
{
Order = order;
}
}
Now having a viewmodel with only one item might seem overkill (and it most likely will be at first). If you need to display more items on your view it starts to help.
public class OrderDetailsViewModel
{
public Order Order {get;set;}
public List<Order> SimilarOrders {get;set;}
public OrderDetailsViewModel(Order order, List<Order> similarOrders)
{
Order = order;
SimilarOrders = similarOrders;
}
}
Repository should work only with models not anonymous types and it should only implement CRUD operations. If you need some filtering you can add a service layer for that.
For mapping between ViewModels and Models you can use any of mapping libraries, such as Automapper.
The current answers are very good. I would just point out that you are abusing anonymous types; they should only be used for intermediate transport steps, and never passed to other places in your code (e.g. view model constructors).
My approach would be to inject the view model with all the relevant model classes. E.g. an action method might look like:
var dinner = dinnerRepository.Get(dinnerId);
var bar = barRepository.Get(barId);
var viewModel = new DinnerAndBarFormViewModel(dinner, bar);
return View(viewModel);
I have the same doubt of the poster and I am still not convinced. I personally do not like very much the given advice of limiting the repository to just executing basic CRUD operations. IMHO, performances should always be kept into account when developing a real application, and substituting a SQL outer join with two different queries for master-detail relationships doesn't sound too good to me.
Also, this way the principle that only needed fields should be queried is completely lost: using this approach, we are forced to always retrieve all the fields of all the tables involved, which is simply crazy in non-toy applications!

Categories