I am working with an EF Code First project, and all is well. I have a simple Class, Customer. In my Customer Class I have a field I want to encrypt (Yes, I know I can encrypt at the DB level but requirements dictate I encrypt at the Domain/Code level), so I am hoping that I can do something like the following:
public class Customer
{
public int CustomerID { get; set; }
public string FieldToEncrypt { get; set { _FieldToEncrypt = MyEncryptionFunction.Encrypt(); } }
}
However, I assume that if the setter has a definition, entity framework code first may ignore that property when generating the schema. So my question is, is there a way to do EF Code First with provided getters/setters, or should I move this functionality into a constructor? Should I override one of the methods/events that happens when the Context is saving, instead?
EDIT ********************
As a note, I am using DataService to transmit the data over an OData protocol service. This automatically generates insert/update/select methods. Some of the suggestions require creating a second property, but the DataService class does not seem to pass through NotMapped properties. This throws a bit of a kink into my earlier question.
public class Customer
{
public int CustomerID { get; set; }
public string EncryptedField { get; private set; }
[NotMapped]
public string Field
{
get { return MyEncryptionFunction.Decrypt(EncryptedField); }
set { EncryptedField = MyEncryptionFunction.Encrypt(value); }
}
}
Related
Consider this simple one to many relationship in Entity Framework. One organisation holds many products.
public class Product
{
public int Id { get; set; }
[StringLength(20)]
public string Title { get; set; }
[StringLength(300)]
public string Description { get; set; }
public float Price { get; set; }
public DateTime CreationDate { get; set; }
public virtual Organisation Organisation { get; set; }
public Product()
{
CreationDate = DateTime.Now;
}
}
public class Organisation
{
public int Id { get; set; }
[StringLength(20)]
public string Title { get; set; }
[StringLength(400)]
public string Description { get; set; }
public DateTime CreationDate { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
If I have a (post) api call, accepting raw data in the body (json formatted text), which allows the user to create an organisation and as many products as they want, in the same call. How do I correctly save these data into the database using Entity Framework?
As far as I know I am using lazy loading (due to virtual keywords when setting relations in the models), so shouldn't it handle relations automatically? If I save the data like in the controller action below (the controller action for the post call). Will it work? And if it doesn't, what is the appropriate/best practice method for saving a model that contains a list of another model using Entity Framework.
public IHttpActionResult CreateOrganisation(Organisation org)
{
db.Organisations.Add(org);
db.SaveChanges();
return Ok(org);
}
Really can't seem to find this in the docs?
Well, i didn´t have time to try it, but looking at your code i see that there are some suggestions that i may point to you if you are looking for the best practices even if these don´t anwser your question:
Make your Web API Controller using the Async Task pattern to avoid dead locks:
public async Task<IHttpActionResult> CreateOrganisation(Organisation org)
Make the caller method, the business logic of your ef, as the same pattern above. In this case use the SaveChangesAsync() method. Don´t forget to use also the keyword await when calling any method as the example above within your controller.
Make the use of the separation of concerns. Apply the BL out of your Controller class.
Apply the SOLID principle. Dependency of inversion, letter D, for example using the Microsfot Unity IOC container, make the classes loosely coupled using abstract classes, interfaces, so after that apply the dependency of injection.
Try to use a View Model to valide the model instead of the domain class generated by the datafirst model or the code first model by the EF.
Last but not least, strongly typed!!!!
I hope these suggestions would help you.
Since you asked for "best practices", I'll tell you about a technique I had to work with back when EF's handling of object graphs was a little, shall we say "iffy"?
First, each physically stored entity has a corresponding DTO object. Part of the ViewModel (MVVM-speak) was the necessary DTO object(s) for that View. There were additional fields added to communicate State (what the UI did) for each entity. It looked something like this:
public class ProductDTO {
// Same fields, mostly
public string Action { get; set; } // A, C, D
}
public class OrganizationDTO {
// Same fields except children
public ICollection<ProductDTO> Products { get; set; }
public string Action { get; set; }
}
Based on non-blank Action in the top level DTO, POST, PUT or DELETE (A,C,D). UI sets the states of each entity. A modification to children counts as a "change" to the parent.
Then in my CRUD methods on the backend ... Admittedly, this is the sledgehammer approach.
public class OrganizationRepository : whatever interfaces {
public void Add (OrganizationDTO newOrg) {
if (newOrg.Action != "A") // Why are you here?
throw an exception (bad request)
context.Organizations.Add(Map DTO to entity here);
foreach (var item in newOrg.Products) {
switch (item.Action)
case "A":
ProductRepository.Add(item,newOrg.Id);
break;
case "C":
ProductRepository.Update(item,newOrg.Id);
break;
case "D":
ProductRepository.Delete(item);
break;
}
context.SaveChanges();
}
public void Update (OrganizationDTO oldOrg) {
if (newOrg.Action != "C") // Why are you here?
throw an exception (bad request)
context.Organizations.Attach(Map DTO to entity here);
foreach (var item in newOrg.Products) {
switch (item.Action)
case "A":
ProductRepository.Add(item,newOrg.Id);
break;
case "C":
ProductRepository.Update(item,newOrg.Id);
break;
case "D":
ProductRepository.Delete(item);
break;
}
context.SaveChanges();
return Ok();
}
}
This is not working/tested code. Just rough off-the-cuff. Have to handle FKs on adds. Add your mapping technique. Handle collisions, Try/Catch, etc.
I think your code is not well self-explaining.
If I'm a developer that looks at the method you posted here, I would simply not understand that i have the possibility to send nested-data.
I would make an iteration over the Products collection of the object "org" and add them to their EF collection, then late add the Organisation to its own.
Then, obviously, SaveChanges().
This would clearly distinguish this method that accept nested object, from another ipothetical that doesn't and simply saves my new empty Organisation.
I'm developing a web app that contains a User entity that is derived from .NET Core's IdentityUser. Lets suppose there is another entity called Comment which has a relation to a user (the user who posted the comment):
public class User : IdentityUser
{
public string SomeExtraField { get; set; }
}
public class Comment
{
//Owner (Creator) of the feedback
public User User { get; set; }
//body of the comment
public string Body { get; set; }
}
Now suppose I have an API endpoint that returns all of the comments in the system. If I query for all comments and include the User relation, when the object gets serialized, everything in the User class is serialized and sent to the client (including the users hashed password, etc). Obviously I don't want this. So I've created a CommentService layer that grabs the Comments from a CommentRepository. From my understanding, the service layer should do the job of mapping the raw Comment object into a Comment DTO, which only contains data that should be sent to the client. I've defined a comment and user DTO like this:
public class UserOutput
{
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
public class CommentOutput
{
public UserOutput User { get; set; }
public string Body { get; set; }
}
Then in my service layer I have something like the following:
//Fetch all comments
var list = await _repository.ListAsync();
//Map comments to DTO
var result = list.Select(x => new CommentOutput
{
Body = x.Body,
User = new UserOutput
{
Id = x.User.Id,
SomeExtraField = x.User.SomeExtraField,
}
});
This all seems to work great. However I can foresee one problem. Lets say I have a large system with Comments, Posts, Likes, Private Messages, etc. I can map them all in a similar fashion above. Then one day I decide to add another field to the UserOutput DTO. Now I have to go through potentially hundreds of mapping code like the sample above to map the new field properly, and whats worse is the compiler wont tell me if I've missed anything. I would like to have a function somewhere that maps a User to a UserOutput but I don't know where it should go.
I've seen some suggestions to put a constructor to the DTO that does the mapping:
public class UserOutput
{
public UserOutput(User user)
{
Id = user.Id;
SomeExtraField = user.SomeExtraField
}
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
but I've seen people against this because it tightly couples the DTO with the Entity. I've also seen suggestions of using Auto Mapper but is also seems an equal amount of people are against it.
Where should I place code that can perform these DTO->entity and entity->DTO mappings so I don't repeat myself all over the place?
Try to check out AutoMapper.
This library will help you to map the Entity Class into the ViewModel.
The way to use it is pretty straightforward.
I'm having a hard time figuring something out that seems as a "easy" problem.
I'm working with Microsoft Azure mobile apps .Net backend, a MSSQL database, Entity Framework code-first and AutoMapper.
So i have the following objects:
public class Route
{
public string Id { get; set; }
[...] //some other properties
public string SerializedGoogleRoute { get; set; }
}
public class DtoRoute
{
public string Id { get; set; }
[...]
public DtoGoogleRoute GoogleRoute { get; set; }
}
public class DtoGoogleRoute
{
[...] //only strings, ints,...
}
So what I want to do is: In the database save the GoogleRoute as a serialized string because it consists of many properties and I don't need them in different columns - I just want it as a serialized string in one column on the route entity.
When the Route object is projected to the DtoRoute object I want the GoogleRoute to be serialized and vice versa.
Because I'm working with LINQ / queryables I am limited to a few AutoMapper mapping options (see AutoMapper wiki). And with none of these I can't get it to work.
The problems I'm facing/what I tried:
I can't serialize/deserialize the string to the DtoGoogleRoute on mapping (with MapFrom or ConstructProjectionUsing) because LINQ obviously cannot transform the JsonConvert.Serialize/Deserialize methods to SQL statements.
I tried having a DtoGoogleRoute property in the Route object and a string property in the DtoRoute object with getters/setters doing the (de)serialization. This works almost perfectly in a custom API controller but because of the OData query filter the azure mobile app .Net backend uses in the tablecontrollers again only the serialized string property gets returned to the client (because OData/LINQ does not know of the other property).
Another option was making a complex type out of DtoGoogleRoute with Entity Framework - this works fine but not with AutoMapper because AutoMapper can't handle complex types.
For now I'm working with a custom API controller and this works. But it would be better to use the tablecontrollers because they support offline sync.
I can't imagine such a simple thing (at least I thought it was a simple thing) can't be done or is so hard to do. But maybe the problem is all the components (tablecontroller, OData, LINQ, EF, AutoMapper) involved.
I would really be thankful if someone could help.
[EDIT]: I think the fact that it works with a normal api controller and not with a tablecontroller has something to do with OData. I tried putting the same code in a tablecontroller method and in an API controller method. when calling the API controller method I can see on the server that it just calls this function and returns all the right properties to the client (checked with fiddler). But when calling the tablecontroller method the tablecontroller method "rewrites" the URL to a OData URL --> I think this is because of some of the EnableQuery or other OData attributes. Because here (although not AutoMapper but it seems like a similar project from Microsoft) it says that the EnableQuery attribute is called twice - also when the request leaves the server. And I think it cuts of the GoogleRoute property because it does not know about this property in the OData metadata or something like that.
You can achieve it like this -
internal class RouteToDtoConverter : TypeConverter<Route, DtoRoute>
{
protected override DtoRoute ConvertCore(Route source)
{
return new DtoRoute
{
Id = source.Id,
GoogleRoute = JsonConvert.DeserializeObject<DtoGoogleRoute>(source.SerializedGoogleRoute)
};
}
}
internal class DtoToRouteConverter : TypeConverter<DtoRoute, Route>
{
protected override Route ConvertCore(DtoRoute source)
{
return new Route
{
Id = source.Id,
SerializedGoogleRoute = JsonConvert.SerializeObject(source.GoogleRoute)
};
}
}
public class Route
{
public string Id { get; set; }
public string SerializedGoogleRoute { get; set; }
}
public class DtoRoute
{
public string Id { get; set; }
public DtoGoogleRoute GoogleRoute { get; set; }
}
public class DtoGoogleRoute
{
public int MyProperty { get; set; }
public int MyProperty2 { get; set; }
}
AutoMapper.Mapper.CreateMap<Route, DtoRoute>()
.ConvertUsing(new RouteToDtoConverter());
AutoMapper.Mapper.CreateMap<DtoRoute, Route>()
.ConvertUsing(new DtoToRouteConverter());
var res = Mapper.Map<DtoRoute>(new Route
{
Id = "101",
SerializedGoogleRoute = "{'MyProperty':'90','MyProperty2':'09'}"
});
var org = Mapper.Map<Route>(res); //pass
In my solution I have two projects.
Project 1 (Core)
Mapping SQL to DTO using Dapper
Project 2 (WebUI - ASP.NET MVC 4)
Here I use a ViewModel per View.
Examples of a Controller
[HttpGet]
public ActionResult Edit(int id)
{
// Get my ProductDto in Core
var product = Using<ProductService>().Single(id);
var vm = new ProductFormModel(product);
return View(vm);
}
Examples of a ViewModel
public class ProductFormModel : BaseViewModel, ICreateProductCommand
{
public int ProductId { get; set; }
public int ProductGroupId { get; set; }
public string ArtNo { get; set; }
public bool IsDefault { get; set; }
public string Description { get; set; }
public string Specification { get; set; }
public string Unit { get; set; }
public string Account { get; set; }
public decimal NetPrice { get; set; }
public ProductFormModel(int productGroupId)
{
this.ProductGroupId = productGroupId;
}
public ProductFormModel(ProductDto dto)
{
this.ProductId = dto.ProductId;
this.ProductGroupId = dto.ProductGroupId;
this.ArtNo = dto.ArtNo;
this.IsDefault = dto.IsDefault;
this.Description = dto.Description;
this.Specification = dto.Specification;
this.Unit = dto.Unit;
this.Account = dto.Account;
this.NetPrice = dto.NetPrice;
}
public ProductFormModel()
{
}
}
Explanation:
I'll get my DTOs in my controller using a service class in the project (Core).
Then i create my ViewModel and pass the DTO to the constructor in ViewModel.
I can also use this view to add a new Product because my ViewModel can take a empty constructor.
Does anyone have experience of this. I wonder if I am in this way will have problems in the future as the project gets bigger?
I know this has nothing to do with Dapper. But I would still like a good way to explain my solution.
I think you will be fine using your current approach. More importantly, start out like this and refactor if you start to encounter problems related to your object mapping code (instead of thinking too much about it beforehand).
Another way to organize mapping logic that I use sometimes is to employ extension methods. That way, the mapping code is kept separate from the view model itself. Something like:
public static class ProductMappingExtensions
{
public static ProductFormModel ToViewModel(this ProductDto dto)
{
// Mapping code goes here
}
}
// Usage:
var viewModel = dto.ToViewModel();
Yet another approach would be to use a mapping framework like AutoMapper - this is a good fit in particular if your mapping logic is simple (lots of 1:1 mappings between properties).
But again, start simple and refactor when you need to.
I realize that this is a little bit late answer, but maybe it will help someone in the future.
This way of doing mapping between objects breaks the 'S' of the SOLID principles, because the responsibility of the ViewModel is to prepare data in its properties to be ready to use by the view and nothing else, therefore, mapping objects should not be on it's responsibilities.
Another drawback of this way is that it also breaks the 'Loose Coupling' OO principle as you ViewModel is strongly coupled with your DTO.
I think, even when we are in the very first step of the project, there are some importants OO principles that we should never break, so using mapper classes, either auto (AutoMapper, ValueInjecter ...) or manual, is definitely better.
How do data frameworks such as Linq 2 SQL, ADO.Net Data Entities and DataSets relate to the "Model" as defined by .Net MVC.
The reason I ask is I'm trying to learn the ins and outs of the .Net framework without relying on many of the tools that make it easy and hide the workings from you.
The "model" I'm building in my exploratory app is simply PostgreSQL commands to update the database. I'm purposefully not using a data "framework".
I'm finding that much of the functionality that comes as part of the .Net MVC framework isn't working for me. Stuff like UpdateModel() and anything related to ModelState doesn't seem to acknowledge what's going on.
Is much of that functionality tied to using Linq 2 SQL or ADO.Net Data Entities? If so, that's fine, I just don't quite understand the relationship yet.
Unlike Views and Controllers, there's not really any restrictions on what the Model is in an ASP.NET MVC app. It just enables you to model the data in your app and clearly and safely express your intent without having to resort to using dictionaries such as ViewData to pass data around.
In terms of the model-related functionality, I believe (not 100% sure) that it is based on having public properties on your model objects. If you call UpdateModel or its relatives, it will set public properties on the model object based on the form data etc. All it does it set properties on that in-memory object if it finds appropriate ones that match form inputs etc. You still need to include the logic to actually persist that to a database or whatever else it is you want to do.
Hope this points you in the right direction at least.
Basically your "Model" object needs to have a parameterless constructor and public get/set properties for it to function easily with the DefaultModelBinder.
Tip: I believe that if you fail to define a parameterless constructor, an empty one is inferred for you (just so you don't freak out: "ahh! i don't hav a parameterless constructor").
So this would generally work fine:
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public string Number { get; set; }
public string Email { get; set; }
}
Figured it out. For the sake of completeness...
Ok, so there is a "minimum standard" for models in .Net.
This is NOT accepted as a model:
namespace MVCApplication.Models
{
public class Person
{
public int ID;
public string Name;
public string Title;
public string Description;
public string Phone;
public string Address;
public string Country;
public Person()
{
}
}
}
This IS accepted as a model:
namespace MVCApplication.Models
{
public class Person
{
private int _ID;
private string _Name;
...
public Person() {}
public int ID { get{ return _ID } set{ this._ID = value } }
public int Name { get{ return _Name } set{ this._Name = value } }
...
}
}
I can't say I completely understand why, but at least now I know.