Storing functions inside model - c#

Let's assume that I have a class Offer which is:
public class Offer
{
[Key]
public int ID { get; set; }
//...
public virtual List<OfferEventManager> EventManagers { get; set; }
public virtual List<EventDay> EventDays { get; set; }
public virtual List<OfferStatus> OfferStatuses { get; set; }
public virtual List<EstimatedCost> EstimatedCosts { get; set; }
public virtual List<Payment> Payments { get; set; }
}
And I'll have to do some checking, e.g. Someone wants to send an Offer to client, but first Offer has to be in speciffic OfferStatus, some example EventDays and example EstimatedCost. Now let's assume that I'll have to check it not only in one function, but in some more, so I'll need to know what is the latest OfferStatus etc. Should I store a function inside Model e.g. GetLatestStatus() and some other functions or Model should have only properties which are stored in DB? If I can't store functions inside then what is the best way to write some usefull functions which I can use with Offer got from DB call?

You can add method in your model class by partial class public partial class Offer
Can read more at Using partial-classes in Entity Framework with custom properties
What is the best way to write some usefull functions which I can use with Offer got from DB call?
You should follow repository pattern
More reference at https://www.c-sharpcorner.com/article/creating-web-api-with-repository-pattern-and-dependency-injection/
Entity Framework 4 / POCO - Where to start?

Typically, models in EF should be direct models of the database (possibly with some virtual mappings).
I'm not entirely sure what your question is (or what you are wanting), but if all you're wanting is the most recent status, you can do this:
// assume that 'offer' is an Offer from the DB
var latestStatus = offer.OfferStatuses.OrderByDescending(x => x.Timestamp).First();
You can add a "getter" on the model like so:
public class Offer
{
// Getter method
public OfferStatus GetLatestStatus
{
get { return OfferStatuses.OrderByDescending(x => x.Timestamp).FirstOrDefault(); }
set { ; }
}
}

Related

Entity Framework Core 2.0 How to automatically Insert Update Delete an detached entity

I have found a lot of threads discussing this topic but none of them have a good solution or I'm just not able to use better search tags :|
I have a Angular2 Frontend with a ASP.Net Core WebApi2 Backend. The database is connected via Entity Framework Core 2.
My issue is just focussed on the backend with EF Core.
My aim is to have a simple method which takes a detached entity (coming from the frontend) which should be updated to the database.
The entity itself has some properties with a lot of navigation properties and these navigation properties have also a lot of navigation properties.
The database model could look like this:
public partial class Project
{
public Project()
{
DocumentNavigation = new HashSet<Document>();
}
public string ProjectNr { get; set; }
public string ProjectTitle { get; set; }
public ICollection<Document> DocumentNavigation { get; set; }
}
public partial class Document
{
public Document()
{
UserNavigation = new HashSet<User>();
}
public int DocumentId { get; set; }
public string DocumentName { get; set; }
public ICollection<User> UserNavigation { get; set; }
}
public partial class User
{
public int UserId { get; set; }
public string UserName { get; set; }
}
My method looks like this:
[HttpPut]
[Route("{projectNr}")]
public IActionResult UpdateProject(string projectNr, [FromBody]Project project)
{
using (abcContext ctx = new abcContext())
{
DoSomething();
ctx.SaveChanges();
}
return NoContent();
}
How do I have to write the method "DoSomething()" in order to deal with this problem?
Imagine, my new object "project" could have new documents, some documents which are still in the database should be deleted because they are no longer in the parameter object "project" and some documents have just changed its normal propoerties like "DocumentName". This could also has happend to the underlaying UserNavigations ...
I just wanted to keep this sample simple. My original entities and the database is much bigger.
To my mind the EF should have a method like "ctx.Update(project)" which manages all these problems???
I cannot believe that I have to do all this stuff manually.
But just in case of doing it manually, how would it look like?
Thanks very much for your support.

Restrict access to data in OData $expand operation

I have two entities from my database exposed in an ASP.NET WebApi 2 OData: service Employee and Activity. For simplicity, let's assume they look like this:
public class Employee {
public int Id { get; set; }
public string Type { get; set; }
}
public class Activity {
public int Id { get; set; }
public int EmployeeId { get; set; }
public virtual Employee OpenedBy { get; set; }
}
Please note that the OpenedBy property corresponds to a navigation property, e.g. I can run the following OData query:
GET http://localhost/odata/Activities?$expand=OpenedBy
I would like to block certain Employee types from being shown in OData. Let's assume I can't do this on the data source, so I have to do it in code.
What I've done so far is to block these types in the EmployeesController (inherits from EntitySetController):
[Queryable]
public override IQueryable<Employee> Get() {
return dbContext.Employees.Where(e => e.Type != "Restricted").AsQueryable();
}
[Queryable]
protected override Employee GetEntityByKey([FromODataUri] int key) {
var employee = dbContext.Employees.Find(key);
if (employee == null || employee.Type == "Restricted") {
throw new ODataException("Forbidden");
}
return employee;
}
This works fine. However, I noticed that if I run the query:
GET http://localhost/odata/Activities?$expand=OpenedBy
I do not hit the code in the Employees controller and consequently the restricted employee records are visible. What is a good way to prevent this from happening?
In this case: http://localhost/odata/Activities?$expand=OpenedBy
I think you should change the code in ActivitiesController, $expand will hit Get Activity method there.
If you do not want to expand the OpenedBy all the time, you can add an attribute:
[NotExpandable]
Hope this can help :)
Since you say "I noticed that if I run the query" I get the impression that this is a side-effect that you are happy to restrict in all circumstances. If this is the case this article by Mike Wasson could be of use to you.
In that article he suggests two methods to restrict odata access to a property:
An attribute on your model
Programmatically removing it from your EDM
I didn't try the first and I'm not sure which namespace or libraries you would need to do it but, in the case of the question it would look like this:
public class Activity {
public int Id { get; set; }
public int EmployeeId { get; set; }
[IgnoreDataMember]
public virtual Employee OpenedBy { get; set; }
}
I have used the second method and this would look something like this for the example given in the question:
var activities = modelBuilder.EntitySet<Activity>("Activities");
activities.EntityType.Ignore(a => a.OpenedBy);
I have restricted some navigational Collections this way and it works very well.

multiple tables from the same model

I am attempting to use several tables that all follow the same model, this is so that eventually if my application scales farther than needing a single database, the framework has already been laid.
Multiple object sets per type are not supported. The object sets 'Entity' and 'Reddit' can both contain instances of type 'Project.Models.Entity'.
I know this error comes from this section of my dbcontect model:
public DbSet<Entity> Entity {get; set;} //local users
public DbSet<Entity> Reddit { get; set; } //users who registered through reddit
public DbSet<Entity> Twitter { get; set; } //user who registered through twitter
I cant seem to find a way to make this work. I know existing topics cover why this is a problem, but the only solution I seem to find is "well make another database" which while seems simple, still doesn't really explain the issue or how to actually fix it through code.
(using entity framework 6)
This was extracted from the question.
I found the solution and It's so simple I'm rather ashamed that I even had to ask.
just make a new DBcontext for each table
which looks like
RedditDB.cs
public RedditDB() : base("name=Database")
{
}
public DbSet<Entity> Reddit { get; set; }
TwitterDB.cs
public RedditDB() : base("name=Database")
{
}
public DbSet<Entity> Twitter{ get; set; }
and in the controller just put
RedditDB _RDB = new RedditDB();
TwitterDB _TDB = new TwitterDB();
Use inheritance to create a new class with the same properties as the existing Entity.
public class Twitter
{
public int Id { get; set; }
public string Title { get; set; }
public ICollection<EntityC> Lines { get; set; }
}
public class Reddit : Twitter
{
// leave this empty
}
This is better than using separate DB contexts because it is easier to query a single context; you can join tables etc.

MVC Architechture - models and entities

In order to make my web-application project I used some tutorials and downloaded 2 sample projects. I noticed that in both of them entities were imported from the SQL server into the project AND models were created for each related class. From what I understand, the entities represent the database itself while the models are the ones to check validations (for example) and after validations successfully passed, the data is sent in to the entities which in turn get it into the database (?) .
In my project I have no models at all. I thought that the entities represent the models, therefore why shall I create duplicate classes (rather entities and models which both look alike).
All the data annotations are inside the entities classes.
I was told that each change done in the tables inside the SQL server would erase my entire work.
I would like to know whether it's true or not, as well as why do I acctually need models when I have entities instead.
If models ARE needed, how do you acctually pass their data into the entities?
Edit:
I found this post Difference between model and entity which answers most of my question.
I would like to know whether my entire entity class's annotations are erased whenever I change a simple thing in the SQL server.
Why wouldn't the model class be an exact duplicate of the entity class (besides the data annotations)?
The models represents the database entities. Those models shouldn't be responsible for displaying data in views or validating user input - their only usage is to represent some table in a database as a c# object.
Let say you have model:
[Table("Products", Schema = "product")]
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public long CategoryId { get; set; }
public string Description { get; set; }
public string ManufacturerUrl { get; set; }
public string ImageUrl { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
public Category Category { get; set; }
}
Now to make use of it in your views and add some validation if you like then you should create a so called ViewModel for it which could be something like this:
public class ProductViewModel
{
public long Id { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[DataType(DataType.Url)]
[Display(Name = "Producer")]
public string ManufacturerUrl { get; set; }
[DataType(DataType.ImageUrl)]
public string ImageUrl { get; set; }
[DataType(DataType.Currency)]
public decimal Price { get; set; }
[Display(Name = "In stock")]
public int Stock { get; set; }
public CategoryViewModel Category { get; set; }
}
Suppose your entity is Person. You decide to have the Entity as the Model, instead of a different class.
In your view (editing an existing person), there is a dropdownlist with country names (Person needs a Country entity). So, that means that you need a list of all possible countries, so the user can select one.
How do you pass that list of countries?
Well, if you have a separate class that you use as the Model, you can easily add a new property, put the list of countries in that, and then get that from your view.
So your viewmodel for this example would be:
public class PersonEditModel
{
public Person PersonToEdit { get; set; } //This is your entity from before
public List<Country> Countries { get; set; } //Extra data for the view
}
Think of your model as a sort of 'package' that combines your entity with all other needed information that the view requires. In case there is no extra information required, you could forego the Model and keep using the Entity directly.
But most people label this bad practice. What if you need an extra bit of information suddenly? You'd have to rewrite your code to now start implementing a model.
Long story short: If you have no need for extra data in the view, and you're working on a private project; do whatever you think is best. Professionally, I would suggest always using a Model, if only to make sure you can add extra data in the future.
Because as you rightly pointed out, your entities will be erased and recreated if you ever refreshed your edmx file.
You could actually lose the model layer if you use partial classes and put your business rules in there, but the point of having a model layer is that it is much simpler to write unit tests for models than for entities.
I suggest that after you've finished learning the basics, you go on and learn about Domain Driven Development (DDD) and Test Driven Development(TDD). All you questions will be answered then, because if I bombard you with all of the theory now you'd probably get lost or think it's much more difficult than it actually is..

Why would I need to use a virtual modifier in a c# class?

I have the following class:
public class Delivery
{
// Primary key, and one-to-many relation with Customer
public int DeliveryID { get; set; }
public virtual int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
// Properties
string Description { get; set; }
}
Can someone explain why they Customer information is coded with virtual. What does it mean?
Judging by the comments, you are learning Entity Framework?
virtual here would mean you are trying to use lazy loading - when related items like Customer can be loaded by EF automatically
http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx
For example, when using the Princess entity class defined below, the related unicorns will be loaded the first time the Unicorns navigation property is accessed:
public class Princess
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Unicorn> Unicorns { get; set; }
}
Can someone explain why they Customer information is coded with virtual. What does it mean?
The virtual keyword means that a super class derived from this base class (i.e. Delivery) can override that method.
If the method was not marked as virtual then it would not be possible to override that method.
Guess you are using EF.
What happens when you make a NavigationProperty virtual is that EF dynamically creates a derived class.
That class implements functionality that allows for lazy loading and other tasks like maintaining relations that EF performs for you.
Just to get the idea your sample class dynamically becomes something like this:
public class DynamicEFDelivery : Delivery
{
public override Customer Customer
{
get
{
return // go to the DB and actually get the customer
}
set
{
// attach the given customer to the current entity within the current context
// afterwards set the Property value
}
}
}
You can easily see this while debugging, the actual instance types of your EF classes have very weird names, since they are generated on the fly.

Categories

Resources