I have these classes:
class User
{
public int Id { get; set; }
string Email { get; set; }
}
class Model1
{
Model2 Model2 { get; set }
Model3 Model3 { get; set }
User User { get; set; }
}
class Model2
{
User User2 { get; set; }
}
class Model3
{
User User3 { get; set; }
}
(In practice the Model hierarchy is deeper and has many other properties. The important thing is that the User class is referenced in several different places of the Model hierarchy.)
I am in the process of mapping this class hierarchy using EF. I am forced to use two distinct relational databases, a legacy "UserDB" which already maps the User class, but which I otherwise cannot touch; and a "ModelDB" which is under my control. Similarly, I can change the Model[123] but not the User class(es). Client code using Model[123] must have access to a User User property.
EF does not support inter-database joins. I tried to emulate one, like this: I added a int UserId field accompanying User User to all of Model[123], then marked User User as [NotMapped]. The question is when to resolve these ids into actual User objects. The options seem to be:
Manually fixup the Model hierarchy by traversing it and loading missing User User properties immediately after each EF query to ModernDB.
Make the User User properties lazy, and have them resolve upon first access.
Neither option seems good: Option (1) is error prone and repetitive; Option (2) introduces what should be asynchronous operations in calls that client code should be able to assume is asynchronous. (Also, I seemed to very easily introduce deadlocks when I tried.)
Does EF have a hook that allows me to run asynchronous code when an EF-entity is populated?
Is there a good way to emulate inter-database joins in EF?
Related
Do not know how to use the advanced features of displaying thing here, so please excuse ;-)
The database structure is
User --> UserOwnerR <-- Owner
Also I have several support structures (ex. addresses belonging to a specific owner).
I need to find all addresses to whom a specific user has access because it belongs to on/many owners, but not addresses to whom the user have a owner relation.
n:m relations can be realized without a join table in EF Core 5+.
public class User
{
// user properties
public IEnumerable<Owner> Owners { get; set; }
}
public class Owner
{
// owner properties
public IEnumerable<User> Users { get; set; }
}
You did not specify wether you’re using ef Code first approach (you generated your Schema based on c# classes) or database first approach (generate c# classes from database tables) or none of those (manually set up your entities).
If you are able to change your classes manually, you might add navigation properties. Those might look like this:
public class User
{
// whatever
public IEnumerable<UserOwnerR> userOwners { get; set; }
}
public class Owner
{
// whatever
public IEnumerable<UserOwnerR> userOwners { get; set; }
}
public class UserOwnerR
{
public virtual Owner owner { get; set; }
public virtual User user { get; set; }
}
Now you are able to place conditions while joining those tables together. Use the sql syntax based query option with linq, as it’s easier to connect your tables that way. You might want to take a look at Entity Framework Join 3 Tables to construct your individual query.
currently the identity models are hard coded and the models inherit from them, however I'd rather be able to just write generic models without having to specify the identity properties like this (because I would need a different model definition for the same model, depending on the storage type)
PersonModel : CouchAdapterModel, IJsonModel {
string Name { get; set; }
}
CouchAdapterModel : IJsonModel {
string _id { get; set; }
string _rev { get; set; }
}
thus PersonModel gains those two inherited properties, and will be in the serialized Json accordingly as needed for couch
but let's say that I don't want to use inheritance for this, rather I want the identity properties to be implied or added at runtime based on the chosen document store
then I can define the model generically, but then if I want to save it or read it from something other than CouchDB it will gain the identity properties accordingly
Can't think of a super clean way to do this though... one thought was have some kind of IJsonIdentity property required then it would be injected at runtime like
CouchDBIdentity : IJsonIdentity {
string _id { get; set; }
string _rev { get; set; }
}
or
MongoDBIdentity : IJsonIdentity {
string whatever { get; set; }
}
and then at runtime when the model provider creates the model the dependency injection or something sets the identity property on the model...
the problem then becomes that I can no longer get the properties at the root level of the model, instead they are underneath the Identity property of that model, so standard JSON for the backend won't match up and people can't just use it as expected...
any idea would be greatly appreciated
I have the following ViewModel:
public class InvitationViewModel
{
public int id { get; set; }
public string InvitationName { get; set; }
public string Type { get; set; }
public string RSVPStat { get; set; }
public virtual List<Guests> guests { get; set; }
}
I want to add some validation for the List of Guests, is it possible to use data annotations for this or is there some other way?
Thanks for any suggestions.
Since your question is a little unclear, I'll round the bases. You can add some validation to the list itself, if that's what you're looking for. That pretty much just includes Required, which would validate that the list has at least one item:
[Required]
public List<Guests> Guests { get; set; }
The keyword virtual allows a property, method or field to be overridden by a subclass. Most likely, you saw this on your entity and figured you need the same here in your view model. The reason entities use virtual on reference and navigation properties is that Entity Framework creates proxy classes of your entities in order to provide lazy-loading functionality. The proxies (which are just subclasses) override the reference and navigation properties to insert the lazy-loading code necessary.
If you're talking about adding validation attributes to the properties of the actual Guest class, you cannot do that just for the sake of a view model. Any validation you add to Guest will be for any use of Guest. There's nothing stopping you from also implementing a GuestViewModel or similar class, though, which you could then add whatever validation you like to.
Do you want to validate each guest? In that case mark Guest up with Data annotations. If you want a validation on the list itself (i.e. number of guests), you can write you own ValidationAttribute, or you can implement IValidateableObject on your model.
Edit: if your view model requires different validation, create a GuestViewModel and mark it up with the required validation.
Right now I have proxy creation disabled:
context.Configuration.ProxyCreationEnabled = false;
I have a data model like so (removed non-relevant fields):
public partial class Video
{
public int VideoID { get; set; }
public string Title { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
}
public partial class User
{
public User()
{
this.Videos = new HashSet<Video>();
}
public int UserID { get; set; }
public string Username { get; set; }
public virtual ICollection<Video> Videos { get; set; }
}
I am using Unit of Work and Repository patterns to load my data like so,
Get all video's, including the user object:
var videos = videoService
.Include(v => v.User)
.Get()
I am using automapper to map from data model to domain model (hence the UI namespace in the screenshot below). When I inspect the video enumeration I get back, and look at the first item in the enumeration, I go to check the user object:
What I expect here is the VideoModel to be filled with data(ok), with only it's single UserModel entity to be filled with data(ok), and all collections in the UserModel to be empty(this is broke). As you can see in the second red box above, the Videos collection is populated with 6 videos. And on those video's, the user's are filled in. So this basically creates a very large object graph.
1) Can I make it so when using an include that it ONLY goes 1 level deep (IE doesn't fill in Video.User.Videos)?
2) Why doesn't ProxyCreationEnabled = false take care of this? Am I expecting too much?
p.s. I want to avoid creating a customer mapper for this with automapper.
p.p.s. I am doing db first, not model first
By default, EntityFramework uses lazy loading for virtual properties (such as User and Videos in your example). If you want these properties to be filled prior to them actually being accessed, you can use Include() or, to go another level deep, an Include() with a nested Select().
This default behavior, however, relies on the creation of a proxy class, which you have apparently turned off.
Not knowing all the things you're trying to do, this may not work, but it seems like you would get the behavior you wanted by simply removing ProxyCreationEnabled = false and using Include() as you have.
Also, viewing properties in the debugger may be misleading because you are in fact accessing the property when you try to view it in the debugger (which could cause the lazy loaded entity or collection to be filled right then, making you think it had been eagerly loaded).
Need a little help please if anyone can shed some light on this.
I've created a code-first MVC 3 application which I have working fine. I'm refactoring now to remove as much coupling as possible as I want the domain model to be used in various other MVC 3 applications later on. What I have now is a collection of entities which are persisted via a normalised database and they are CRUD-ed through a repository pattern. I have used Ninject to DI the repositories via the controller's constructor and am using models within the MVC 3 project to act as DAOs.
So, within the domain I have an entity called Case that has a foreign key to another case Client that looks like this:
public class Case : ICase
{
[Key]
public int CaseId { get; set; }
public string CaseName { get; set; }
public DateTime DateCreated { get; set; }
public IClient Client { get; set; }
}
Then I have an interface (the interface exists mainly to implement it to the view model to add my data annotations - I know I could add the annotations to the domain object but as I said I want to use this domain model in other applications which will have a different ubiquitious language.
public interface ICase
{
int CaseId { get; set; }
string CaseName { get; set; }
DateTime DateCreated { get; set; }
IClient Client { get; set; }
}
And then I have my view model within the MVC 3 project.
public class CaseModel : ICase
{
[HiddenInput(DisplayValue = false)]
int CaseId { get; set; }
[Required(AllowEmptyStrings = false)]
[MaxLength(100)]
string CaseName { get; set; }
[RegularExpression("")]
DateTime DateCreated { get; set; }
IClient Client { get; set; }
}
So, my first problem is this: changing my foreign key reference for Client to IClient is a new thing, and it returns a null object. When the type was a concrete class it returned fine - I assume this is because EF4.1 tries to create an instance of IClient. Am I totally wrong here or is there a way around this?
My second problem (which may negate my first problem) is am I also doing something wrong by adding data annotations to a view model inheriting the interface of my domain entity? Should I be using model meta data? If so, how do I use meta data in such a way that I can make the data annotations unique to each project without touching the domain?
Thanks!
Caveat: I'm not an expert on EF or MVC3.
We're in the process of building EF Code First entities, and we're not planning on adding interfaces to the entities. Repositories get interfaces. Units of Work get interfaces. Entities don't. Repositories return concrete entities, which are POCOs. Entities may be coupled to related entities. Models and other classes will typically get repository interfaces and/or unit of work interfaces injected in. For testing, we'll just new up some POCO entities and return them from the mock repositories.
We're planning to make the relevant POCO properties virtual so that EF can create proxies.
If you want to decouple a view from concrete entities, I'd first ask what value you expect to gain from that. Is the view going to be reused with different entities? If so, one option would be to use something like AutoMapper to copy the properties over. You'd have to be aware of the immediate access of lazy-load properties, though.