I have a good understanding of EF, and generated my database successfully. Now, I am struggling with adding dynamic properties to one of the entity classes. For example, I have a Post class, and other users can make comments to the posts. When I list the existing posts, I want to display the number of comments made to corresponding post.
One solution might be having a property called CommentCount, and updating the Post by increasing the (int) value of the CommentCount property by 1 when a new comment is made.
The other solution, and I think it is a better solution, is that when retrieving the post from the DB, the number of comments associated with the post can be computed and retrieved at the same time and assigned to CommentCount property of the post instance. However, I do not know how to achieve this with EF.
Which approach is highly recommended? Or, is there any other ways of doing this? If it is the second one, how can I achieve this with EF?
1) You should simply consider not putting the property called CommentCount into your model. When you develop for example a WPF Windows application, you should consider using MVVM pattern and the CommentCount would belong to your ViewModel class and not to your Model class. There you implement INotifyPropertyChanged and you can use it from your frontend Views. Analogically there is MVC pattern for ASP.NET etc.
There are other design patterns like Repository pattern. Using this pattern you can create the CommentCount in your repository class and not in your
model class. This would be similar to your second solution.
2) I assume from your question that you are using code-first approach:
generated my database successfully
If you do so and you wish to include CommentCount directly in your Model class, you can do it this by adding partial class file to your project like this:
namespace DBModel.Models
{
public partial class Post
{
public int CommentsCount
{
get { return this.Comments.Count; }
}
...
But I cannot see why to create extra property in your model just for that.
On the other hand adding this field as a computed field into your SQL database could make sense and then it would be part of your EF model.
If you calculation is very complex you should try creating a View in your DB and then add it to your Model?
But if your Model have something simple like
class Post {
public int postid { get; set; }
public virtual ICollection<comment> comment { get; set; }
}
In your controller you can do
db.post(x => x.postid == yourid).comments.count()
to get total of comment
or in your view
#foreach (var item in Model)
{
<li>item.postid;</li>
<li>item.comment.Count();</li>
}
Or update your class
class Post {
public int postid { get; set; }
public virtual ICollection<comment> comment { get; set; }
public int CommentCount
{
get
{
return comment.Count();
}
}
}
Just remember bring related data in your query.
In my case POI have properties parish_id, sector_id, city_id and parish have municipality, and municipality have state.
Using this query I can get Poi with all the related data.
filter = db.poi
.Include("parish")
.Include("sector")
.Include("city")
.Include("parish.municipality")
.Include("parish.municipality.state")
.Where(x => x.sector_id == SectorID);
Related
I just recently started creating a .net web app in mvc5. I've tried to search for the answer as I usually do rather than asking a question but Im not sure how to word this but here it goes:
I have a class:
public partial class employee
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
In which the class was created by using the Database First wizard with Entity Framework. (reasoning for the tag)
What I did was get the FistName, MiddleName, and LastName from the database. In which I successfully did with this ActionResult from my controller.
[ChildActionOnly]
public ActionResult Nav()
{
employee user;
using (DatabaseEntities context = new DatabaseEntities())
{
user = context.employees.FirstOrDefault(e => e.FirstName ="Bob");
if (!System.IO.File.Exists(Server.MapPath(user.imagefile)))
{
user.imagefile = $"/Content/Images/user/{user.FirstName[0]}.png";
}
}
return PartialView("_Nav", user);
}
Now I'm wondering if its possible, how to create another item to the class without adding a column to the database. I want to add a FormattedName variable to the class that is got after the database call to get the model (user) to include the new variable (FormattedName) that gets its value from the existing variables in the class.
I understand the wording and terminology could be off but any help would be great and thx in advance.
Edit:
In the comment section, I was informed about attributes ex.[NotMapped] which was information I definitely needed to know. But for this particular question, it doesn't work. Everything was ok until I updated the model using entity framework, the attributes were gone and have to keep adding them every model update which is not ideal for me. I went ahead and edited my database to include a (FormattedName) column so the problem is fixed. But I still would love to know if this is doable.
I have a model that has some related data in navigation properties, like so:
public class Document
{
[Key]
public int DocumentId { get; set; }
public string DocumentName { get; set; }
public virtual ICollection<DocumentBeneficiary> DocumentBeneficiaries { get; set; }
public virtual ICollection<DocumentExecutor> DocumentExecutors { get; set; }
public virtual ICollection<DocumentSuccessor> DocumentSuccessors { get; set; }
}
I understand how to do eager loading of this related data from a controller method, like so:
var doc = context.Documents.Include(x => x.DocumentBeneficiaries)
However, what I want to do is write a member method inside the model that takes the data related to an entity, does some processing, and outputs a string. Something like this:
public class Document
{
...
public string ProcessStuff() {
//use data in navigation properties here like so:
foreach (var d in DocumentBeneficiaries) { ... }
}
}
Is this allowable? I can't seem to find anything about it on google. Will it load the related data lazy vs. eager depending on how I load the entity in the controller prior to calling the method in the model?
I realize that some schools of thought hold that models should have no methods, but others say it's ok to put business logic in the model. If I have to I suppose I can make this a controller method, but this way makes more sense to my design if possible. Sorry if this is a somewhat speculative question, but I can't seem to find any info on this pattern.
Yes it will load the DocumentBeneficiaries when you invoke ProcessStuff method as long as Lazyloading is enabled, thou it may not be a good design (my opinion) to add business logic directly into the model, but as you stated, there are some who like it and some who don't.
If you don't load the child collection ahead of time using Include and Lazyloading is enabled, then you will end up making extra database trips while executing ProcessStuff(). Using Include pre loads the data you need with less number of database round trips. It is always better to make less database trips whenever possible.
If Lazyloading is disabled, you have to use Include before invoking ProcessStuff()
Can you tell Entity Framework to add an extra field for each field of a certain type? For example: Is it possible to generate a ChangedAt datetime field for each boolean field defined in the model, so this
public bool Confirmed { get; set; }
could result in a table with an additional field ConfirmedChangedAt where the value is updated each time the boolean value is changed.
Usually behavior like this should be implemented directly into your business logic and not automatically into the data layer. So I suggest to write something like this:
// entity
public class Order
{
public bool Confirmed { get; set; }
public DateTime? ConfirmedAt { get; set; }
}
// business logic
public class OrderManager
{
.................
public void Confirm( Order order )
{
// changing of entity status
order.Confirmed = true;
order.ConfirmedAt = DateTime.Now;
// storing new entity status
_orderRepository.Update( order );
................
}
}
I think if i understand you correctly, You are expecting the Entity Framework to be able to add columns to the database automatically so that you don't have to add them manually, Well you have 2 cases:
if you are using the database first approach you could achieve this
by using a query that's specific to your needs to add these columns
for you based on the conditions you have.
If you are using the code first approach and you have an existing database you may reverse engineer the database using the Entity Framework Power Tools and you could customize the T4 Templates to generate the entities with the extra properties that you need.
Plain answer no.
But it's depend on way how you interact with EF (code first, model first,database first).
If you using EF 6 and code first approach you can use idea of base Entity class
public class BaseEntity
{
public DateTime ChangedAt {get;set;}
}
public class ConcreteEntity : BaseEntity
{
public string Name {get;set;}
}
Now ConcreteEntity has ChangedAt by inheritance.
If this solution not for you, please explain question with more details.
I'm trying to develop a messeging system to my mvc application using mvc 5. I have tables called Event, EventUser, EventObject. Each of those tables have following;
Event
ID
CreatedBy
StartTime
IsShared
Budget
EventUser
EventID
UserID
IsAccepted
EventObject
EventID
ObjectID
in my messageController i have the index method which receive the parameter of the user id.i need to display every event that user has invited using this method..
namespace MvcApp.Controllers
{
public class MessageController : Controller
{
private EPlannerDatabaseEntities db = new EPlannerDatabaseEntities();
// GET: /Message/
public ActionResult Index(int UId)
{
/* linq expressions */
return View();
}
}
}
when the parameter has passed in, i want to;
*Select from EventUser table where UID=UserID and join the result with Event and EventObject tables by using EventID attribute.
*Finally by using the final result i need to display every event's infomation that user has invited; like CreatedBy , StartTime, Budget,other users,objects etc..
i'm new to mvc and viewmodel concept.I heard that viewmodel concept can help with these situations.can i overcome this problem by using viewmodel concept.if yes what are the things i need to add in view model?? otherwise what are the other ways to do this?
one way i can see of doing this is creating a custom return object and using EF to join all the tables together. Example
public class MyObject{
public DateTime DateCreated{get;set}
// add remaining properties here
// properties to get back
}
then in code you would use Entity Framework to create a joined data set into a nice list of objects. Example:
var results = (from b in bla join bla2 in (Some Second Query Here)
from SomeSecondQueryHere
where cond1 and cond2 Select new MyObject{
// add properties in here})
where you would replace the bla and bla2,etc with respective table names needed. Then all you need to do is
return View(results);
And the changes will be accessible in the View
If you question is regarding querying with an ORM like Entity Framework, you need to post your entities, not your table schemas. The whole purpose of an ORM is to abstract away the underlying database structure, so while the schema will often be similar to the entity class, it can also be quite different. As a result, I'll have to make assumptions about your entity classes.
To query everything, you just need something like the following:
var events = db.Events.Where(m =>
m.EventUsers.Any(u => u.UserID == UId && u.IsAccepted)
).Include(m => m.EventObjects);
That assumes entity classes along the lines of:
public class Event
{
...
public virtual ICollection<EventObject> EventObjects { get; set; }
public virtual ICollection<EventUser> EventUsers { get; set; }
}
public class EventUser
{
...
public int UserID { get; set; }
public bool IsAccepted { get; set; }
}
You end up with an enumerable of Event. If you need to access the EventObjects for an individual event, you have to use the appropriate collection property. For example:
foreach (var item in events)
{
foreach (var obj in item.EventObjects)
{
// do something with `obj` (an invidual `EventObject` instance)
}
}
If you need the actual User object, you're better object querying that first and including related Events and EventObjects:
var user = db.Users.Include("EventUsers.Event.EventObjects").SingleOrDefault(m => m.UserID == UId);
That assumes entities like:
public class User
{
...
public virtual ICollection<EventUser> EventUsers { get; set; }
}
public class EventUser
{
...
public virtual Event Event { get; set; }
}
public class Event
{
...
public virtual ICollection<EventObject> EventObjects { get; set; }
}
With that method, however, there's no way to filter the included Events by whether they're accepted or not. There's a potential way around that, but it requires disabling lazy-loading of EventUsers entirely and complicates querying the information you need. If you need to go that route, see: https://msdn.microsoft.com/en-us/data/jj574232.aspx#explicitFilter.
Otherwise, you can just exclude non-accepted events before iterating over the collection:
var events = user.EventUsers.Where(m => m.IsAccepted).Select(m => m.Event);
Really you don't need a view model, per se, for any of this. As you can either pass the lists of events (which will include any related EventObjects) or the the single user instance (which includes related events and related EventObjects) directly to your view.
A very high level description of how to solve your scenario using Entity Framework would be something like this:
First you've got to create a series of entity data objects that will represent your tables in the EF data model using EF Code first techniques.
Then you create DbContext objects with DbSets for your previously created entities.
Then you create at least one Service class that will have a property representing DbContext and a set of methods encapsulating Linq queries to your entities.
In the MVC controller you call an instance of Service that you previously create and assign it to a property ant Controller's construction time. Finally, in the Action method you should call the correct Service method and pass any result to the view.
( I am assuming this is a small Ad-Hoc system with a handful of tables , an elaborate System with production quality would require using IoC techniques).
I've got a situation where I have data classes that are generated by a database with various properties on them e.g which I cannot modify.
public DataClass
{
public string PropertyX {get; set;}
public int PropertyY {get; set;}
public float PropertyZ {get; set;}
}
Some of these classes may have 20 or so properties. When updating the data a "transient" copy of the "persistent" data is made, then the properties updated on the transient and copied from the transient to persistent.
Which is fine although if only changing one property isn't very efficient.
I wanted to find out if there is a way in c# that I could create a list of flagged properties or add attributes onto certain flagged properties I wish to update.
So the end result would be (please note this is all pseudo)
DataClass transientObj = new DataClass(Transient);
[FlagPropertyToUpdate] //This is the bit I have no idea how to do
transientObj.propertyX = "updateOnlyMe!";
DataClass persistantObj = new DataClass(Persistant);
UpdateData dataUpdater = new UpdateData(transientObj,persistantObj)
dataUpdater.save();
public UpdateData
{
public void save(){
//some how know to only update propertyX and not all three properties
}
public UpdateData(DataClass trans, DataClass pers)
}
Any assistance on how I could go about doing this (and if its possible) would be highly appreciated!
I'd recommend creating a DTO (Data Transfer Object) that supports dirty-flagging the relevant properties. That way your classes can remain unchanged. Have a look at Automapper.
Then again, I'd invite you to reconsider your assertion that updating the complete set of properties is inefficient, assuming they're simple types. Writing to an entire row in a database is generally no more expensive than writing a single column. I'd be more concerned wth concurrency in the situation you describe.
I think View Model's will fit here.
The ViewModel is an abstraction of the View or a conceptual state of the data as opposed to the real state of the data in the Model.
So in this case you will have a class like:
public DataClassViewModel
{
//Define all relevant properties here.
...
public DataClassViewModel(DataClass model) //Constructor
{
//Initialize the view model from the model.
}
public DataClass GetModel()
{
//Depending on changes in the view model, model could be updated here.
}
public void UpdateData()
{
}
}
You can read more about view model's here:
Model-View-ViewModel (MVVM) Explained
How we do MVC – View models
What is ViewModel in MVC?
Although the articles point to MVC/MVVM UI architectures, view model is quite a general concept.