Creating a computed property with Entity Framework 6 - c#

I am using Database First approach and I have created model from a database. Now I have a datagrid view in my Winforms app, that is bound to a binding source. And all that works fine (an appropriate data is shown in datagrid view). Now the problem is, how to add a computed property that consists of two values (already found in db) ? For an example:
Lets say that I have a table user (id, username, first_name, last_name, user_type) but I want to have different columns in my bound datagrid view, and I want to have these columns:
username, full name, type
where "full name" is what would I get with first_name + " " + last_name.
I guess I can't just modify a model class manually like this:
public string FullName
{
get
{
return FirstName + " " + LastName;
}
protected set {}
}
because this class is generated automatically , and my code will be deleted each time a generate models from an existing database (when I make some change), so this is not the real option...

Actually, I solved this by using partial class functionality:
I have created another file that contains another portion of my User model class (with my additional properties) and everything went just fine.
namespace User.Model
{
public partial class User
{
public string FullName
{
get
{
return (this.firstName + " " + this.lastName;
}
protected set { }
}
}
}
Now when I generate model classes, this new file is not affected by EF. Also this new field is correctly shown by datagrid view...

I still cant add comments, so I will have to do it this way.
Regarding your approach, why don't you create a data transfer model that you will bind to the data grid view?
With this approach, your new model will have the needed property FullName and you can show this in your grid view. You database entity model will remain the same. With this, you have decoupled the database model from the view model and achieved what you wanted.
UPDATE:
/// <summary>
/// Assuming this is the EF model, generated with the database first approach. We leave it as is.
/// </summary>
public class UserEntityModel
{
public int Id { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int UserType { get; set; }
}
/// <summary>
/// This model represents your grid presentation specific data. As you can see, we have the fields
/// that we will show. This is the new DTO model
/// </summary>
public class UserGridViewModel
{
public string UserName { get; set; }
public string FullName { get; set; }
public int UserType { get; set; }
}
/// <summary>
/// This method demonstrates the retrieving and model to model mapping.
/// </summary>
public UserGridViewModel GetUser(int userId)
{
//retrieve the UserEntityModel
var efObject = _context.User.Where(user => user.Id == userId).SingleOrDefault();
if (efObject == null) {
return null;
}
// construct the new object, set the required data
return new UserGridViewModel()
{
UserName = efObject.UserName,
UserType = efObject.UserType,
FullName = $"{efObject.FirstName} {efObject.LastName}"
};
}
Additional explanation:
Let's assume that UserEntityModel is your database first generated data model. we will leave it as is.
We will create a second model, UserGridViewModel that contains data only that you will show in your grid. This is the DTO model.
The GetUser Method should conceptually demonstrate the usage of the first (ef model) and then the second (DTO) model. We retrieve the data from the database, we construct the DTO model and pass it to the grid.
You can find more information here and here.
Hope this helps, cheers and happy coding!

Related

.NET Core Razor event after Model Binding for modifications?

What I'd like to achive is to be able to modiy certain (string) values after they were binded to a property but they are being validated in .NET Core 3.1.
Example poco class:
public class MyPoco
{
[TrimContent]
[MinLength(2)]
public string? FirstName { get; set; }
[TrimContent]
[MinLength(2)]
public string? Surname { get; set; }
[TrimContent]
[LowerCase]
public string? EmailAddress { get; set; }
}
So let's say a form is posted to the MVC controller and the values entered are
" F " for the first name and " S " as the surname, " My.Email#Address.Com ".
They should be modified, i.e. trimmed to "F" and "S" and the MinLength=2 should be alerted i.e. Also: I can avoid all the Trim() statements in my code.
My idea is, that when using a "TrimContentAttribute" (and other attributes that "correct" the values in some way), all values that have been set by previous BindingSourceValueProviders and then are being processed, but before the validation kicks in.
Also attributes marked with LowerCase, should automatically be "ToLower()", so the email address would be "my.email#address.com".
So it the idea would be to declrative approch other than having all the Trim() und ToLowerCase() methods all over the code where the entity is used.
The only idea I came up with so far to write a custom source as described in
Model Binding in ASP.NET Core - Additional sources. But I actually would like to rely on all the default values providers.
Note: There are validators on client side in action as well, but I'd like to have a solution also on the server side.
a new attribute can be created
public class MinLengthWithTrim : MinLengthAttribute
{
public MinLengthWithTrim(int length) : base(length)
{
}
public override bool IsValid(object? value)
{
var str = value as string;
if (str == null)
{
return false;
}
return base.IsValid(str.Trim());
}
}
Using:
[MinLengthWithTrim(10)]
public string Name { get; set; }

Mapping a User entity into a User DTO in .NET Core

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.

Wpf - How to control observable collection updates

In the parent there is a Observable Collection PendingPayment that has a list of all pending payments of sales with a column amount paid.
Then the user can select a particular sale and open it in new child window.
The thing thats going wrong is if the user just edits the text box paid amount in child window and closes the window without saving the new paid amount to database,the observable collection containing Amount paid column in the parent window gets updated.
What I want is it the collection to get updated only when the values are updated in the database.
This can be achieved by creating a copy of your sale object when the user select it in the list, and then using this copy as the view model of your child view.
You will then be able to set the new values in the original object from your list only once the save button has been clicked and the database update succeed.
An other way to proceed if you need to edit only few of the object properties would be to create and editor object and use it as the child window's view model.
Something like this :
public class Sale
{
public int PaidAmount { get; set; }
public int Some { get; set; }
public int More { get; set; }
public int Properties { get; set; }
}
public class SaleEditor
{
private Sale _sale;
public int PaidAmount { get; set; }
public SaleEditor(Sale sale)
{
_sale = sale;
PaidAmount = sale.PaidAmount;
}
public void Save()
{
// update your data here
_sale.PaidAmount = PaidAmount;
}
}
If you need your original object to update the database, then the save method could first update the object and the revert the changes if DB update failed :
public void Save()
{
var oldAmount = _sale.PaidAmount;
_sale.PaidAmount = PaidAmount;
if (!SalesDB.Update(_sale))
_sale.PaidAmount = oldAmount;
// you could also read back the value from DB
}
Whenever possible (I've never see a reason why it cannot),for listing purpose use proxy or flatted objects, you can implement this using projections query. Then user select an item from a list and the only thing you need to grab is a key to load the full object with its required object graph as the use case might dictate.
Here is a sample implementation using Entity Framework and c# lambda expressions:
Using anonymous object:
var anonymousListProjection = DbContext.PendingPayments.Select( pp=>
new { pp.Order, pp.Amount})
Using a hardcoded proxy:
var hardcodedListProjection = DbContext.PendingPayments.Select( pp=>
new PendingPaymentProxy { Order = pp.Order, Amount = pp.Amount})
//To return an observable:
var observableColl = new ObservableCollection<PendingPaymentProxy>
(hardcodedListProjection.Tolist());
public class PendingPaymentProxy
{
public string Order { get; set; }
public decimal Amount{ get; set; }
}
Apart from avoiding possibles performance problems due to unintentional loading real objects, this way you only have to worry for your list when the user do save in the detail view.

How to "inject" a property and its value to an object

The goal
"Inject" a property and its value to an object.
The problem
I have the following object that is created by Entity Framework 5:
public partial class getSpecificProductToShoppingList_Result
{
public string productName { get; set; }
public string measureAbbreviation { get; set; }
}
I'm creating a Shopping List using Session and when an user adds something to his list, the application calls a procedure to get the information about this product and these information populate the above properties respectively.
The point is: the user can add the the amount of products he wants — and it is not responsibility of the database.
To add a product, the user must to access MyApp.com/Products/Add?productId=1&quantity=5. I can retrieve all the information about the product using this:
ShoppingListController.cs:
public ActionResult Add(Nullable<int> productId, int quantity)
{
if (Session["ShoppingList"] == null)
{
Session["ShoppingList"] = new
List<getSpecificProductToShoppingList_Result>();
}
getSpecificProductToShoppingList_Result product =
Products.BuildItemToShoppingList(productId);
((List<getSpecificProductToShoppingList_Result>)Session["ShoppingList"])
.Add(product);
return View("Index");
}
And then, the view:
#foreach (var item in
(List<MyApp.Models.Data.getSpecificProductToShoppingList_Result>)
Session["ShoppingList"])
{
<p>#item.productName | #item.measureAbbreviation</p>
}
My question is simple: how can I add something like #item.quantity?
What I'm thinking about
I'm thinking in something like this (pay attention to line after product variable declaration):
public ActionResult Add(Nullable<int> productId, int quantity)
{
if (Session["ShoppingList"] == null)
{
Session["ShoppingList"] =
new List<getSpecificProductToShoppingList_Result>();
}
getSpecificProductToShoppingList_Result product =
Products.BuildItemToShoppingList(productId);
((List<getSpecificProductToShoppingList_Result>)Session["ShoppingList"])
.Insert(productId,
new KeyValuePair<string, int>("quantity", quantity))
.Add(product);
return View("Index");
}
But — of course — no success. The syntax is wrong, but was just to illustrate.
Details
I'm using C#.Net + MVC 4 + Razor Engine
In the same namespace as your entity framework model, ie. the same folder you put the .edmx file, make a new Class with the same name as the class the one defined in the entity framework, which I think in your case is getSpecificProductToShoppingList_Result.
Mark the class as partial, and you can add properties of your own to it.
Eg: you have this in your .edmx designer file:
[EdmEntityTypeAttribute(NamespaceName="YourModel", Name="getSpecificProductToShoppingList_Result")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class getSpecificProductToShoppingList_Result : EntityObject
{
...
}
This is auto generated and you can't alter it to add some properties, but it's marked as partial to let you expand on it, eg. if I add:
public partial class getSpecificProductToShoppingList_Result
{
public int Quantity {get; set; }
}
C# joins them together, so in my controller, I can do
var something = new List<getSpecificProductToShoppingList_Result>();
something.First().quantity = 50;
Quantity doesn't belong to getSpecificProductToShoppingList_Result because that is my database type, but I have added it via a partial class.

Custom serialization/deserialization over a field with Entity Framework 4

I'm in charge to migrate our own DAL to a solution based on Entity Framework 4 but, before I can do it, I need to be sure it's possible to translate all our "constructs" to this new technology.
One of the biggest issues I'm having is the possibility to read a field and build a custom type. Valid examples could be a bit mask saved in a BIGINT field, a list of mail addresses saved as a CSV list in a NVARCHAR field or an XML field containing aggregated data not worth to have their own table/entity. Basically the serialization mechanism is not fixed.
Let's take the classic "Address" example.
public class Address
{
public string Street {get; set;}
public string City {get; set;}
public string Zip {get; set;}
public string Country {get; set;}
}
and let's suppose we want to save it in an XML field using this template:
<address>
<street>Abrahamsbergsvägen, 73</street>
<city>Stockholm</city>
<zip>16830</zip>
<country>Sweden</country>
</address>
The question basically is: does exist a method to override how EF4 serializes and deserializes the content of a field mapped to a property of an entity?
I found this solution. It's not as clean as I wished but it seems it's impossible to get anything better.
given this base entity,
public class Institute
{
public int InstituteID { get; set; }
public string Name { get; set; }
// other properties omitted
}
I added in the database an XML field called Data containing some strings using this simple template
<values>
<value>Value 1</value>
<value>Value 2</value>
<value>Value 3</value>
</values>
In the entity I added these properties and I mapped the database field "Data" to the property "DataRaw".
protected string DataRaw
{
get
{
if (_Data == null)
return _DataRaw;
else
return new XElement("values", from s in Data select new XElement("value", s)).ToString();
}
set
{
_DataRaw = value;
}
}
private string _DataRaw;
private string[] _Data;
public string[] Data
{
get
{
if (_Data == null)
{
_Data = (from elem in XDocument.Parse(_DataRaw).Root.Elements("value")
select elem.Value).ToArray();
}
return _Data;
}
set
{
_Data = value;
}
}
This solution works. Here is the sample code:
class Program
{
static void Main(string[] args)
{
var ctx = new ObjectContext("name=TestEntities");
var institute = ctx.CreateObjectSet<Institute>().First();
System.Console.WriteLine("{0}, {1}", institute.InstituteID, institute.Name);
foreach (string data in institute.Data)
System.Console.WriteLine("\t{0}", data);
institute.Data = new string[] {
"New value 1",
"New value 2",
"New value 3"
};
ctx.SaveChanges();
}
}
Does anyone have a better solution?
Entity Framework does NOT serializes or deserializes entities nor it controls how the serialization should take place in other layers or modules of your application.
What you need to do is to simply open your POCO(s) and annotate their Properties with appropriate attributes that will be taken into account at the time of serialization when you want to ship them to your other application layers.

Categories