I'm using repository pattern with LINQ, have IRepository.DeleteOnSubmit(T Entity). It works fine, but when my entity class has interface, like this:
public interface IEntity { int ID {get;set;} }
public partial class MyEntity: IEntity {
public int ID {
get { return this.IDfield; }
set { this.IDfield=value; }
}
}
and then trying to delete some entity like this:
IEntity ie=repository.GetByID(1);
repoitory.DeleteOnSubmit(ie);
throws
The member 'IEntity.ID' has no supported translation to SQL.
fetching data from DB works, but delete and insert doesn't. How to use interface against DataContext?
Here it is:
Exception message:
The member 'MMRI.DAL.ITag.idContent' has no supported translation to SQL.
Code:
var d = repContent.GetAll().Where(x => x.idContent.Equals(idContent));
foreach (var tagConnect in d) <- error line
{
repContet.DeleteOnSubmit(tagConnect);
(it gets all tags from DB, and deletes them)
And stack trace:
[NotSupportedException: The member 'MMRI.DAL.ITag.idContent' has no supported translation to SQL.]
System.Data.Linq.SqlClient.Visitor.VisitMember(SqlMember m) +621763
System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) +541
System.Data.Linq.SqlClient.SqlVisitor.VisitExpression(SqlExpression exp) +8
System.Data.Linq.SqlClient.SqlVisitor.VisitBinaryOperator(SqlBinary bo) +18
System.Data.Linq.SqlClient.Visitor.VisitBinaryOperator(SqlBinary bo) +18
System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) +196
System.Data.Linq.SqlClient.SqlVisitor.VisitExpression(SqlExpression exp) +8
System.Data.Linq.SqlClient.SqlVisitor.VisitSelectCore(SqlSelect select) +46
System.Data.Linq.SqlClient.Visitor.VisitSelect(SqlSelect select) +20
System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) +1024
System.Data.Linq.SqlClient.SqlProvider.BuildQuery( ...
When I try do decorate partial class:
[Column(Storage = "_idEvent", DbType = "Int NOT NULL", IsPrimaryKey = true)]
public int idContent
{ get { return this.idEvent; } set { this.idEvent=value; } }
it throws error "Invalid column name 'idContent'."
It appears Microsoft dropped support for == operator in interfaces when using linq-to-sql in MVC4 (or maybe it was never supported). You can however use i.ID.Equals(someId) in place of the == operator.
Casting IQueryable to IEnumerable works but should not be used! The reason is: IQueryable has funky implementation of IEnumerable. Whatever linq method you'll use on a IQueryable through the IEnumerable interface will cause the query to be executed first, have all the results fetched to the memory from the DB and eventually running the method localy on the data (normally those methods would be translated to SQL and executed in the DB). Imagine trying to get a single row from a table containing billion rows, fetching all of them only to pick one (and it gets much worse with careless casting of IQueryable to IEnumerable and lazy loading related data).
Apparently Linq has no problem using == operator with interfaces on local data (so only IQueryable is affected) and also with Entity Frameworks (or so I heard).
This works for me -
public partial class MyEntity: IEntity
{ [Column(Name = "IDfield", Storage = "_IDfield", IsDbGenerated = true)]
public int ID
{
get { return this.IDfield; }
set { this.IDfield=value; }
}
}
Try this:
using System.Data.Linq.Mapping;
public partial class MyEntity: IEntity
{ [Column(Storage="IDfield", DbType="int not null", IsPrimaryKey=true)]
public int ID
{
get { return this.IDfield; }
set { this.IDfield=value; }
}
}
For translating your LINQ query to actual SQL, Linq2SQL inspects the expression you give it. The problem is that you have not supplied enough information for L2S to be able to translate the "ID" property to the actual DB column name. You can achieve what you want by making sure that L2S can map "ID" to "IDField".
This should be possible using the approach provided in answers.
If you use the designer, you can also simply rename the class property "IDField" to "ID", with the added benefit that you won't have to explicitly implement the "ID" property in your partial class anymore, i.e. the partial class definition for MyEntity simply becomes:
public partial class MyEntity: IEntity
{
}
Related
I'm trying to create a function that generically loads the related child entities with a filter.
All my entities are derived from my own Base Class "BusinessObject"
public abstract class BusinessObject : BaseObject, IBaseObject, ILocalObject
{
[Browsable(false)]
[Key]
public int ID { get; set; }
[Browsable(false)]
public int? HqID { get; set; }
private bool _deleted;
[Browsable(false)]
public bool Deleted
{
get { return _deleted; }
set { CheckPropertyChanged(ref _deleted, value); }
}
}
I have created the following function that when supplied an entity will load all the related child objects.
When defining my entities, all child collections are flagged by my own attribute "EntityChildCollectionAttribute" so I can easily find the collections I want to load.
public virtual void OnLoadEntityChildren(object entity)
{
var propNames = entity.GetPropertyNames();
foreach (var propName in propNames.Where(propName => entity.PropertyHasCustomAttribute(propName, typeof(EntityChildCollectionAttribute))))
{
MyData.Entry(entity).Collection(propName).Load();
}
}
This works lovely!
My Problem comes when I want to filter the child collection.
In this case I want to only load child entities where Deleted == false.
I cannot work out how to do this!
I have had many attempts and replacing MyData.Entry(entity).Collection(propName).Load(); with
MyData.Entry(entity).Collection(propName).Query().Cast<BusinessObject>().Where(x=>x.Deleted.Equals(false)).Load();
compiles but then I get the error;
"Unable to cast the type 'FmOrderProcessing.Entities.OpDocumentDetail' to type 'FwBaseEntityFramework.BusinessObject'. LINQ to Entities only supports casting EDM primitive or enumeration types."
Any Help/Pointers/Answers will be gratefully received
Thanks in advance
Lance
I was implementing a "Soft Delete" pattern which means the records in the database are flagged as deleted rather than removed (for audit and replication purposes).
All entities are derived from a base definition with a bool Deleted property.
I found the answer here:
https://www.nuget.org/packages/EntityFramework.DynamicFilters
This package allows the definition of global filters in the data context.
I fixed my issue with one line of code in the OnModelCreating override.
modelBuilder.Filter("Deleted", (IBaseObject d) =>d.Deleted, false);
The filter function is applied globally to any entity presenting (in my case) the IBaseObject interface.
I hope this helps any body else with a similar issue
I have the following class:
public class BicycleSellerListing : IUserName
{
public UserProfile UserProfile { get; set; }
/// <summary>
/// IUserName interface property
/// </summary>
public string UserName
{
get
{
return UserProfile.UserName;
}
}
}
The interface:
public interface IUserName
{
string UserName { get; }
}
And this query:
public static List<T> GetList<T>(string userName) where T : class, IUserName
{
using (SqlUnitOfWork work = new SqlUnitOfWork())
{
return work.GetList<T>(row => row.UserName == userName)
.ToList();
}
}
When I execute this query, I get the following exception:
The specified type member 'UserName' is not supported in LINQ to
Entities. Only initializers, entity members, and entity navigation
properties are supported.
I understand why I'm getting the exception, but am wondering if there is a way I can perform this query using the interface?
To answer you quistion:
Is it possible to query on an interface property?
Yes. it's no problem. The fault you are getting is not becuase of the interface.
The problem is that you can't query on properties that isn't mappe with Linq 2 Entities
Other people have had this propblem as well.
The underlying expressionbuilder can not distinct between properties that is mapped to the database, and properties that is not.
It is a problem becuase the compiler can't help you.
In Linq to object, it is no problem, so the compiler doesnt throw any errors/warnings
You should try to make it clear the this property is not mapped - perhaps by a prefix, or a nested class that contains all the "custom" properties.
In addition to the existing answer(s), you can perform the where in memory, but that means retrieving the whole table.
Normally I wouldn't recommend this though.
public static List<T> GetList<T>(string userName) where T : class, IUserName
{
using (SqlUnitOfWork work = new SqlUnitOfWork())
{
return work.GetList<T>()
.AsEnumerable()
.Where(row => row.UserName == userName)
.ToList();
}
}
Some workarounds:
You could try to determine underlying entity type in runtime and
then dynamically compile and invoke a generic method executing query
with this type.
It is possible to assemble this query manually in runtime using
Expression class
You could try Entity SQL query syntax instead of Linq
Inspired by a desire to be able to use enumerations in EF queries, I'm considering adding an ExpressionVisitor to my repositories that will take incoming criteria/specifications criteria and rewrite them to use the corresponding persisted int property.
I'm consistently using the following Value-suffix pattern in my (code-first) entities:
public class User : IEntity
{
public long ID { get; set; }
internal int MemberStatusValue { get; set; }
public MemberStatus MemberStatus
{
get { return (MemberStatus) MemberStatusValue; }
set { MemberStatusValue = (int) value; }
}
}
And map this to the database using the following:
internal class UserMapping : AbstractMappingProvider<User>
{
public override void DefineModel( DbModelBuilder modelBuilder )
{
// adds ToTable and other general mappings
base.DefineModel( modelBuilder );
Map.Property( e => e.MemberStatusValue ).HasColumnName( "MemberStatus" );
}
}
In my repositories I have the following method:
public IQueryable<T> Query( Expression<Func<T, bool>> filter, params string[] children )
{
if( children == null || children.Length == 0 )
{
return Objects.Where( filter );
}
DbQuery<T> query = children.Aggregate<string, DbQuery<T>>( Objects, ( current, child ) => current.Include( child ) );
return filter != null ? query.Where( filter ) : query;
}
I'd like to add a method call inside this method to rewrite the filter expression, replacing all references to the MemberStatus property with references to MemberStatusValue.
I suppose it will be a solution involving something like seen in this SO post, but I'm not sure exactly how to get from idea to implementation.
If you can give any advice on the potential performance impact of adding this feature, that would also be appreciated.
I'm not sure whether this is quite what you're after, but I've found it simpler to handle enums in a similar but slightly different way. To wit, I have two properties, as you do, but my int property is public and is what the database persists; I then have another public "wrapper" property that gets/sets the int property value via casts from/to the desired enumerated type, which is what's actually used by the rest of the application.
As a result, I don't have to mess around with the model; EF understands and persists the int property just fine while the rest of the application gets nice interactions with the enum type. The only thing I don't like about my approach is that I have to write my LINQ statements with a bunch of casts on any enum value I'm trying to query to turn it into an int to match against the field that's actually persisted. It's a small price, however, and I'd like to suggest it to you because it appears to me that you're using a string to generate your query which gives up all the type safety, Intellisense, etc. that LINQ provides.
Finally, if you're interested in a walkthrough of how to use the new enum features in EF 5 (which is available in beta for download now if you'd like to try it out), check this out:
http://msdn.microsoft.com/en-us/hh859576
I have a datacontext, and it has Authors table.
public partial Author:IProductTag{}
I want to cast Table<Authors> object to Table<IProductTag>, but that appears to be impossible. I am trying to do that because I want my method to be able to work with different tables which come as input parameters. To be more specific, I need to execute OrderBy and Select methods of the table. I have few other tables, entities of which implement IProductTag . Also, I tried to write a function like:
public static void MyF<t>(){
Table<t> t0 = (Table<t>)DataContext.GetMyTableUsingReflection();
}
But it fails at compile-time. And if I cast the table to something like ITable or IQueriable, then the OrderBy and Select functions simply don't work. So how do you deal with it?
I suspect you want to make your method generic - so instead of
void DoSomethingWithTable(Table<IProductTag> table)
you should have
void DoSomethingWithTable<T>(Table<T> table) where T : class, IProductTag
That should work fine, assuming you only need to read entities (and apply query operators etc). If that doesn't work for you, please give more details about what your method needs to do.
(You say that your attempt to use reflection failed, but you haven't said in what way it failed. Could you give more details?)
I have no idea what a ProductTag is so I've used different types to show my solution to this problem. Yes there doesn't seem to be a way to get a Table<T>, but you can get IQueryable<T> which works just as well (at least for my situation).
I have a simple analytics database, where each website has its own table containing both generic and specific items. I wanted to use an interface for the shared data.
public interface ISession
{
public DateTime CreateDt {get; set; }
public string HostAddress {get; set; }
public int SessionDuration {get; set; }
}
public static IQueryable<ISession> GetQueryableTable(MyDataContext db, string site)
{
Type itemType;
switch (item)
{
case "stackoverflow.com":
itemType = typeof(Analytics_StackOverflow);
break;
case "serverfault.com":
itemType = typeof(Analytics_ServerFault);
break;
default: throw Exception();
}
return db.GetTable(itemType).Cast<ISession>();
}
You can then do a query like this :
var table = GetQueryableTable(db, "stackoverflow.com");
var mySessions = table.Where(s => s.HostAddress == MY_IP);
To create a new row you can use reflection :
var rowType = typeof(Analytics_ServerFault);
var newRow = (ISession) rowType.GetConstructor(new Type[0]).Invoke(new object[0]);
(I have a function to get GetRowType - which is not shown here).
Then to insert into the table I have a separate helper function:
public static void Insert(MyDataContext db, ISession item)
{
// GetTable is defined by Linq2Sql
db.GetTable(GetRowType(domain)).InsertOnSubmit(item);
}
I hope my wording makes sense... I wasn't quite sure exactly how to explain what I'm looking to do.
I have a method in a generic class that returns a list of entities as follows:
public abstract class ChildCRUDController<TModel> : CRUDController<TModel, ... >
where TModel : IChildEntity
public ViewResult List(int id)
{
return View(repository.GetMany(x => x.ParentID == id));
}
This controller is implemented by quite a few other controllers. The issue I have is that not all entities that implement IChildEntity have the same parent type. To get around this issue I created ParentID properties for all the models that implement IChildEntity so they could use the same controller.
public partial class PhoneNumber : IChildEntity
{
public int ParentID
{
get { return CustomerID; }
set { CustomerID = ParentID; }
}
}
and...
public partial class Transaction : IChildEntity
{
public int ParentID
{
get { return LeaseID; }
set { LeaseID= ParentID; }
}
}
But when I call the List method above I get the following error:
The specified type member 'ParentID' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
Is there any way I can achieve the result I am looking for without pulling the object set into memory or renaming all the properties on the entities themselves?
Thanks!
If you are willing to pass the field name into the List method and to construct your own query you can do it using the techniques described in this StackOverflow article:
Querying Entity with LINQ using Dyanmic Field Name
Or you could supply the ChildCRUDController with another generic type parameter constrained to an interface that supplies the field name and again use it dynamically.