Like I mentioned in this question, I wanted to rename some auto generated properties.
So I use the following partial class
public partial class Plan
{
public Profile Creator
{
get { return this.Profile; }
set
{
this.Profile = value;
}
}
public Profile Guest
{
get { return this.Profile1; }
set
{
this.Profile1 = value;
}
}
}
to avoid using Profile1 and Profile. It works but I can't use these new properties in a where clause because they are not mapped (well that's my guess).
Example:
myQuery.Where(x => x.Creator.User.UserName == userName)
I have the following exception
The specified type member 'Creator' is not supported in LINQ to
Entities. Only initializers, entity members, and entity navigation
properties are supported.
I tried to map the property like this but without any success
[Column("creator_id", TypeName="int")]
public Profile Creator
{
get { return this.Profile; }
set
{
this.Profile = value;
}
}
Is it possible?
i think you are looking for something like this
[ForeignKey("creator_id")]
public virtual Profile Creator { get; set; }
These things you commonly use for a code first approach. If you have an existing database you can reverse engineer your code first. check out http://msdn.microsoft.com/en-us/data/jj200620.aspx for an example. That way you can use the fluent API toolkit and an existing database. the best of two worlds.
Related
I'm implementing soft deletion in my app with IsDeleted column, and use EF 6 Code First for ORM. I want to filter deleted entities automatically when using dot operator for accessing lazy loading navigation properties (with many relationship).For example: a User has many Roles
public class User
{
private ICollection<Role> _roles;
public virtual ICollection<Role> Roles
{
get { return _roles?? (_roles= new List<Role>()); }
protected set { _roles= value; }
}
}
and I need that when I use user.Roles, it will auto filter deleted entities, so I won't write it explicitly like because it will happen at many places:
user.Roles.where(u => u.IsDeleted == false).ToList();
I'm thinking about EF Interceptor, but it would apply for all queries and I still want to load deleted entities in some places because of business requirement.
Is there any other way to achieve this efficiently?
Thank you.
You can just add a "more proper" property to encapsulate the logic:
public class User
{
private ICollection<Role> _roles;
public virtual ICollection<Role> Roles
{
get { return _roles ?? (_roles = new List<Role>()); }
protected set { _roles = value; }
}
public IEnumerable<Role> ActiveRoles
{
get { return this.Roles.Where(u => !u.IsDeleted); }
}
}
Usage:
IEnumerable<Role> roles = user.ActiveRoles; // easy
I am assuming your objects ultimately implement some IDeletable or something.This was omitted
You may also consider implementing an extension method IEnumerable<IDeletable> Active() and the clutter will be moved to the usage part: user.Roles.Active(). Can't really tell which approach will be more elegant for your case.
I work on a project where we was using SqlConnection, SqlCommand and plain SQL to access repository. Now, I am trying to migrate to Linq2Sql and I want to use the same models. How can I achieve this?
I will reduce the project structure to the minimal meaningful example.
Let's say I have the following classes:
namespace Model
{
public class User
{
public int Id { get; set; }
}
}
All models in Model namespace are one-in-one copy of database entities.
namespace Repository
{
public class UserRepository
{
private _sqlConnectionHelper = new SqlConnectionHelper();
public User GetUser()
{
var reader = _sqlConnectionHelper
.ExecuteAndReturnReader("SELECT * FROM [dbo].[Users]");
while (reader.Read())
{
return new User
{
Id = (int)reader["Id"]
};
}
return null;
}
}
}
Now I am trying to migrate to Linq2Sql. I have created a MyContext.dmbl file with User table in Repository project. It has generated the following class:
namespace Repository
{
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Users")]
[global::System.Runtime.Serialization.DataContractAttribute()]
public partial class User: INotifyPropertyChanging, INotifyPropertyChanged
{
private int _ID;
public int ID
{
get
{
return this._ID;
}
set
{
if ((this._ID != value))
{
this.OnIDChanging(value);
this.SendPropertyChanging();
this._ID = value;
this.SendPropertyChanged("ID");
this.OnIDChanged();
}
}
}
// Some other methods
}
}
Now, the problem is that I have a lot of of entities, repositories, models etc. I don't want to change the whole project to use new generated models but not mine from Model namespace. How can I make Linq2Sql work with my models?
It also affects my architecture because in case of these models, the entity and the repository is the same object. I don't need my entities to be CRUD objects. I just want to make minimal changes to project and only use convenient LINQ requests instead of plain SQL like this:
namespace Repository
{
public class UserRepository
{
private MyContextDataContext _myContext = new MyContextDataContext();
public User GetUser()
{
return _myContext.Users.FirstOrDefault();
}
}
}
Or I just don't understand something about purpose and logic of Linq2Sql and it is how it only works like?
Of course, I can write converters or use reflection and make a copy of object property-by-property but it doesn't sound like a good solution.
Ok. Finally, I have found an answer which is pretty simple - Linq2Sql is not a library I was looking for.
There are different approaches for object-relational mapping: code-first, database-first, model-first.
Here is the good StackOverflow article about their differences.
Now, when I learned it, what I have described in my question could be easily rephrased as "how can I make Linq2Sql be code-first". The answer is simple - I cannot do this.
As a result of some investigations, I have understood that I was looking for Entity Framework which perfectly fit in my project.
Now, my repository looks like this:
namespace Repository
{
public MyContextDataContext : DbContext
{
public DbSet<User> Users { get; set; }
}
public class UserRepository
{
private MyContextDataContext _myContext = new MyContextDataContext();
public User GetUser()
{
return _myContext.Users.FirstOrDefault();
}
}
}
I have defined an enum in my Entity Framework 5 model, which I'm using to define the type of a field on a table, e.g.
public enum PrivacyLevel : byte {
Public = 1,
FriendsOnly = 2,
Private = 3,
}
And I have a table Publication that has a tinyint field PrivacyLevel, which I've mapped in the EF model to use the PrivacyLevel type defined above, using the method described here.
But I also want to be able to display a string description for each value of the enum. This I've done in the past for enums by decorating them with a Description attribute, e.g.
public enum PrivacyLevel : byte {
[Description("Visible to everyone")]
Public = 1,
[Description("Only friends can view")]
FriendsOnly = 2,
[Description("Only I can view")]
Private = 3,
}
I've got some code that converts enums to strings by checking if they have a Description attribute, and that works well. But here, because I had to define the enum in my model, the underlying code is auto-generated, and I don't have anywhere stable to decorate them.
Any ideas for a workaround?
Not sure if this is what you are after but from what I understand i will try to be as clear as possible, since you have a concrete database first approach, you can abstract much of your Entity models to ViewModels using a Dto Approach through AutoMapper.
Using automapper profiles you can quickly setup profiles for all sorts of environments and scenarios for flexibility and adaptability
So here is this "Enum" which is causing me a problem
here is my view model for this Enum
First here is my layout
here is a simply mapping for the Account entity to a viewmodel for Account
public class AccountProfile : Profile
{
protected override void Configure()
{
// Map from Entity object to a View Model we need or use
// AutoMapper will automatically map any names that match it's conventions, ie properties from Entity to ViewModel have exact same name properties
Mapper.CreateMap<Account, AccountViewModel>()
.ForMember(model => model.CurrentPrivacy, opt => opt.MapFrom(account => (PrivacyLevelViewModel)account.PrivacyLevel));
Mapper.CreateMap<Account, EditAccountViewModel>()
.ForMember(model => model.SelectedPrivacyLevel, opt => opt.MapFrom(account => (PrivacyLevelViewModel) account.PrivacyLevel));
// From our View Model Changes back to our entity
Mapper.CreateMap<EditAccountViewModel, Account>()
.ForMember(entity => entity.Id, opt => opt.Ignore()) // We dont change id's
.ForMember(entity => entity.PrivacyLevel, opt => opt.MapFrom(viewModel => (PrivacyLevel)viewModel.NewSelectedPrivacyLevel));
}
}
Note that this does not have to apply to MVC, this can be used in WPF or other applications not tied to the Web, but since it's a good way of explaining, it's why I used MVC for this example.
When I first get a Http Get request for my profile, I grab the entity from the database
and map anything I actually need to the view
public ActionResult Index()
{
// Retrieve account from db
var account = new Account() { Id = 1, Name = "Patrick", AboutMe = "I'm just another dude", ProfilePictureUrl = "", PrivacyLevel = PrivacyLevel.Private, Friends = new Collection<Account>() };
// ViewModel abstracts the Entities and ensures behavour that only matters to the UI
var accountViewModel = Mapper.Map<AccountViewModel>(account);
return View(accountViewModel); // strongly typed view model
}
So my profile index view can use my enum view model
Here's the output
Now when I want to change what my privacy setting is, I can create a new EditAccountViewModel which allows me to submit a new value in a dropdown
public class EditAccountViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string AboutMe { get; set; }
public int NewSelectedPrivacyLevel { get; set; }
public PrivacyLevelViewModel SelectedPrivacyLevel { get; set; }
public SelectList PrivacyLevels
{
get
{
var items = Enum.GetValues(typeof (PrivacyLevelViewModel))
.Cast<PrivacyLevelViewModel>()
.Select(viewModel => new PrivacyLevelSelectItemViewModel()
{
Text = viewModel.DescriptionAttr(),
Value = (int)viewModel,
});
//SelectPrivacyLevel was mapped by AutoMapper in the profile from
//original entity value to this viewmodel
return new SelectList(items, "Value", "Text", (int) SelectedPrivacyLevel);
}
}
}
Now once I send a post of my new changed value, the interesting part is how I modify the "real" entity from the db with the updated privacy setting
On submitting the form back to my edit action you can i get the original real db entity and then merge changes if the ViewModel state is valid
AutoMapper allows you to configure how ViewModels can be mapped to Entities,
if some properties should change, from integer entities to string values for view models,
maybe you want an enum to really be a string in the "view" and only the enum for the db,
with auto mapper it allows you to configure all these scenarious, and through convention
you dont need to configure "every single property" if your view models have the same
property names/camel case to upper case.
Lastly, before you can use these Profiles, you must load them at the application entry point, like global.asax or Main.
AutoMapper only needs to be 'configured' once to load any sort of profiles defined in the application. With some reflection you can load all Profiles in your assembly with this code:
public class AutoMapperConfig
{
public static void RegisterConfig()
{
Mapper.Initialize(config => GetConfiguration(Mapper.Configuration));
}
private static void GetConfiguration(IConfiguration configuration)
{
configuration.AllowNullDestinationValues = true;
configuration.AllowNullCollections = true;
IEnumerable<Type> profiles = Assembly.GetExecutingAssembly().GetTypes().Where(type => typeof(Profile).IsAssignableFrom(type));
foreach (var profile in profiles)
{
configuration.AddProfile(Activator.CreateInstance(profile) as Profile);
}
}
}
I call the configuration in my global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
AutoMapperConfig.RegisterConfig(); // AutoMapperConfig.cs
}
More information about how to use AutoMapper and how it can benefit you can be found
here:
AutoMapper Github
In the end I came up with a much simpler solution: I just used an extension method to get the description of the enum. That also made it a lot easier for localization, so I could use a Resource string.
public static string Description(this PrivacyLevel level) {
switch (level) {
case PrivacyLevel.Public:
return Resources.PrivacyPublic;
case PrivacyLevel.FriendsOnly:
return Resources.PrivacyFriendsOnly;
case PrivacyLevel.Private:
return Resources.PrivacyPrivate;
default:
throw new ArgumentOutOfRangeException("level");
}
}
Some other idea:
Use byte PrivacyLevelByte in your EF classes. Create additional partial class for that particular model where you define property
PrivacyLevel PrivacyLevelEnum
{
get { return (PrivacyLevel)PrivacyLevelByte; }
set { PrivacyLevelByte = (byte)value;}
}
and define PrivacyLevel enum in your code and not by EF designer.
That allows you to handle any attributes but still gives you enum properties on EF models.
I have the following two entities (using Code First) in my application:
public class Note
{
public int NoteId { get; set; }
public string Text { get; set; }
}
public class Decision
{
// PK/FK
public int NoteId { get; set; }
// other fields ...
public virtual Note Note { get; set; }
}
I configured my relationship like this:
modelBuilder.Entity<Decision>().HasRequired(d => d.Note).WithOptional();
A Decision must have a note but a Note does not always have a decision. A 1:1 mapping with one side being optional.
I would like a property on my note that lets me know if there is a decision for it. Something like:
public bool HasDecision
{
get
{
// not sure what to do here
}
}
Is there a way to do this without having Decision be a lazy loaded property on Note?
You would need to do an explicite query. There is no such thing like "lazy loading proxies for scalar properties". Lazy loading is only supported for navigation properties. Your entity must have a reference to a context if you want to have HasDecision as a property on the entity. I would prefer to create a repository or service method like so:
public bool HasDecision(Note note)
{
return _context.Decisions.Any(d => d.NoteId == note.NoteId);
}
I have a POCO domain model which is wired up to the entity framework using the new ObjectContext class.
public class Product
{
private ICollection<Photo> _photos;
public Product()
{
_photos = new Collection<Photo>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual IEnumerable<Photo> Photos
{
get
{
return _photos;
}
}
public void AddPhoto(Photo photo)
{
//Some biz logic
//...
_photos.Add(photo);
}
}
In the above example i have set the Photos collection type to IEnumerable as this will make it read only. The only way to add/remove photos is through the public methods.
The problem with this is that the Entity Framework cannot load the Photo entities into the IEnumerable collection as it's not of type ICollection.
By changing the type to ICollection will allow callers to call the Add mentod on the collection itself which is not good.
What are my options?
Edit:
I could refactor the code so it does not expose a public property for Photos:
public class Product
{
public Product()
{
Photos = new Collection<Photo>();
}
public int Id { get; set; }
public string Name { get; set; }
private Collection<Photo> Photos {get; set; }
public IEnumerable<Photo> GetPhotos()
{
return Photos;
}
public void AddPhoto(Photo photo)
{
//Some biz logic
//...
Photos.Add(photo);
}
}
And use the GetPhotos() to return the collection. The other problem with the approach is that I will loose the change tracking abilities as I cannot mark the collection as Virtual - It is not possible to mark a property as private virtual.
In NHibernate I believe it's possible to map the proxy class to the private collection via configuration. I hope that this will become a feature of EF4. Currently i don't like the inability to have any control over the collection!
The way to do this is to have a protected virtual property which is mapped in your model and a public property that returns an IEnumerable.
public class Product
{
public Product()
{
PhotoCollection = new Collcation<Photo>();
}
public int Id { get; set; }
public string Name { get; set; }
protected virtual ICollection<Photo> PhotoCollection {get; set; }
public IEnumerable<Photo> Photos
{
get { return PhotoCollection ; }
}
public void AddPhoto(Photo photo)
{
//Some biz logic
//...
PhotoCollection .Add(photo);
}
}
Anton, it would help me understand your problem more if you can explain why is it that you do not want developers to access the Add method of your collection. Is this because the list is strictly read-only, or is it because you want to run some custom business logic when a new entity is added?
Anyway... I am going to assume that you are trying to do the latter (i.e. run custom business logic when the collection is modified). I have done a similar solution on a project of mine, and the idea is as follows:
The TT template that produces POCOs in EF4 creates all collections as TrackableCollection lists. This class has an event called 'CollectionChanged' which you can subscribe to and listen to any changes to your collection.
So you can do something as follows:
public class Product
{
public Product()
{
Photos.CollectionChanged += ListCollectionChanged;
}
public int Id { get; set; }
public string Name { get; set; }
public TrackableCollection<Photo> Photos
{
get
{
// default code generated by EF4 TT
}
set
{
// default code generated by EF4 TT
}
}
private void ListCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
// A new item has been added to collection
case NotifyCollectionChangedAction.Add:
{
T newItem = (T) e.NewItems[0];
// Run custom business logic
}
break;
// An existing item has been removed
case NotifyCollectionChangedAction.Remove:
{
T oldItem = (T) e.OldItems[0];
// Run custom business logic
}
break;
}
}
}
The nice thing about the above solution is that you still use your Product entity in an 'EF' manner... were any developer in your team can simply access a property of the entity directory and need run an explicit hard typed function.
Bit late to the party but this is what Observable objects are for. Allow the data structure to do what it does best. Use ObservableCollection as your field type if you don't want to build your own collection that does what you need and expose the regular ICollection type from your property. You can run any logic in the parent entity you need when the related entities in the collection change via the CollectionChanged event. If you need to selectively enable or disable modifications it's easy enough to extend an existing collection type or write a proxy collection that allows a call to a method to toggle the mutability of the collection (ISupportInitialize can be used to good effect for representing this ability BTW).
(Apologies for my initial post brevity - I was answering from my phone)
You can construct your collection through a LINQ query over an EF entity set. However, you keep the resulting collection as internal data member to your business class and expose the IEnumerable<Photo> returned by calling AsEnumerable() on the entity set as a result of the public photo.
You could cache the IEnumerable<Photos> internally as well, so that you don't call AsEnumerable() every time your caller asks for the collection. Of course, that means that if the user needs to update the collection through your public methods, you might have to refresh the cached IEnumerable. This might pose small issue if the caller has also cached the pointer to the previous IEnumerable.
Alternatively, if your caller will always work with the full entity set, the EntitySet class (of which all your EF sets will inherit) implements IEnumerable<TEntity>, so you can directly return the entity set to your caller.
Note that if you want the loading of the collection from an EF entity set to happen outside of the scope of your business class, you can make a constructor on your class that takes an ICollection. This way, once you create your object, the collection is sealed in it, and exposed only as an IEnumerable.
Why not try the following and leave use properties?
private ICollection<Photo> photos{get; set;}
public IEnumerable<Photo> Photos
{
get {return (IEnumberable<Photo>)photos;}
}
Alternatively you could use the decorator pattern to encapsulate the class into one which the collection can't be directly modified.