Store bool Property as integer with Npgsql and Entity Framework - c#

I'am using Entity Framework 6.1 with the Npgsql 2.2.5 driver.
Entity
public class MyEntity
{
public bool Deprecated { get; set; }
}
Mapping
public class MyEntityMap : EntityTypeConfiguration<MyEntity>
{
public MyEntityMap ()
{
Property(t => t.Deprecated)
.HasColumnName("status")
.HasColumnType("Integer")
.IsOptional();
}
}
When I try to read something from the Database, I get an exception, that is not directly related to something with mapping:
InvalidOperationException "Sequence doesn't contain any matching element" (translated from german, don't know the exact english text)
Is it possible to store a boolean property as an integer? I did a Workaround with introducing a new property Status of type int, which is mapped to the status column. Then I added the NotMappedattribute to Deprecated, made it return Status != 0 int its getter and setting Status to 1 or 0. It is working, but now I can't use Deprecated in linq queries.
I'd simply change the datatype of the column, but there is a legacy system using this database as well. Introducing a new column and keep both in sync with some database triggers would be a solution, but my model has some of these issues. So I'd like to have a more generic solution.
Is there a better way?

Yeah... same problem here.
I don't think there's a clean way to do it unless you modify the source for the npgsql EF provider.
public static class DbValue
{
public const int FALSE = 0; //or something like this
}
public class MyEntity
{
[Column("Deprecated")]
public integer DeprecatedStatus { get; set; }
[NotMapped]
public bool DeprecatedBool
{
get { this.DeprecatedStatus != 0 }
set { this.DeprecatedStatus = (value ? 1 : 0) }
}
}
//Then in Linq
db.MyEntities.Where(e => e.DeprecatedStatus == DbValue.FALSE);
//and
db.MyEntities.Where(e => e.DeprecatedStatus != DbValue.FALSE);
Oh, hey I just thought of another idea. You could write Expression objects in the code and pass them into your Linq (since IQueryable<> uses expressions)
so like this:
public class MyEntity
{
public static Expression<Func<MyEntity, bool>> IsDeprecated = (myEntity) => myEntity.Deprecated != 0;
public static Expression<Func<MyEntity, bool>> IsNotDeprecated = (myEntity) => myEntity.Deprecated == 0;
public integer Deprecated{ get; set; }
}
//Then in Linq
db.MyEntities.Where(MyEntity.IsDeprecated);
//and
db.MyEntities.Where(MyEntity.IsNotDeprecated);
The reason for using Expressions instead of Func stuff can be a little confusing for novices, but the pattern is certainly easy to follow if you're comfortable with lambda expressions. I've done this kind of thing before and it works. What doesn't work is trying to dynamically create your Expression objects at runtime because something goes awry in the EF code. (only compiler geeks would think to do that anyway)
So the disadvantage here is every time you have an expression in your LINQ that you want to use the Deprecated property, you have to create another static expression object.

Related

Difference between == and .Equals() with Interfaces and LINQ

I recently got a "The mapping of interface member ..... is not supported" error, which I resolved based on this thread. To demonstrate:
public interface IMyInterface { string valueText { get; set; } }
public class MyData : IMyInterface
{
int ID { get; set;}
string valueText { get; set;}
}
public class MyOtherData : IMyInterface
{
long ID { get; set;}
string valueText { get; set;}
}
and
public static IEnumerable<T> GetByValue<T>(string value) : where T : class, IMyInterface, new()
{
using (var context = new DataContext())
{
// The important line
return context.GetTable<T>().Where(x => x.valueText == value);
}
}
Running this code, I'd get a NotSupportedException: "The mapping of interface member IMyInterface.valueText is not supported". However, if I replace the x.valueText == value with x.valueText.Equals(value), this works entirely as expected.
I've solved this in my code, but I want to understand why it behaves this way. Can anyone explain it?
Update: As per my comment below, the LINQ to SQL team closed this as a "Won't fix". I think that means it now counts as a known bug, but one that isn't going to be resolved any time soon. I'd still like to know why it behaves differently in the first place, though.
Apparently the decision to push the query upstream to the server is made based on an incomplete set of rules, and then LINQ-to-SQL finds a construct (an interface) that it can't deal with.
The method call isn't supported by LINQ-to-SQL, so it generates a query to retrieve all records and then uses LINQ-to-Objects to filter them. (Actually, based on your other thread, LINQ-to-SQL may make a special exception for object.Equals and knows how to convert that to SQL).
LINQ-to-SQL probably should fall back to the LINQ-to-Objects behavior when an interface is involved, but apparently it just throws an exception instead.

How do I rewrite query expressions to replace enumerations with ints?

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

cast Table<T> to something

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);
}

Property as parameter? C#

So I've got a whole bunch of options, every different page/tab can have their own local options. We'll have maybe 10-15 pages tabs open tops. I need to implement a way to show the global defaults, weather the all the tabs have consistent values. I'm working on the model/viewmodel portion of a WPF app.
I'd love to find a way that is more elegant since I'm having to cut and past roughly the same code 20+ times and just change property names. Maybe this is the problem Dynamics solve, but right now this feels both wrong and painful.
Here is an example of my current solution:
public class Foo
{
private bool fooVar1;
private bool fooVar2;
//lots of these
private decimal fooVar23;
public Foo()
{
}
public bool FooVar1
{
get;
set;
}
//you get the picture...
}
public class FooMonitor
{
private Foo defaultFoo;
private List<Foo> allFoos;
public FooMonitor(Foo DefaultFoo)
{
defaultFoo = DefaultFoo;
}
public void AddFoo(Foo newFoo)
{
allFoos.Add(newFoo);
}
public void AddFoo(Foo oldFoo)
{
allFoos.Remove(oldFoo);
}
public bool IsFooVar1Consistent
{
get
{
Foo[] tempFoos = allFoos.ToArray();
foreach (Foo tempFoo in tempFoos)
{
if (tempFoo.FooVar1 != defaultFoo.FooVar1) return false;
}
return true;
}
}
}
Or am I approaching this problem entirely incorrectly.
As I'm writing this question (After about 2000 lines of code) I'm thinking of how I read that WPF itself implements Dictionary look ups that crawl up to the parent to see if a Property is present and what the value should be.
Well, for a start you are defining both backing fields which will never be used and automatic properties. This is enough for a simple bool property:
public bool FooVar1 { get; set; }
No need for the private field. This greatly reduces the number of lines in your example.
I'd love to find a way that is more
elegant since I'm having to cut and
past roughly the same code 20+ times
and just change property names.
Code generators exist for exactly this purpose. But if you don't want to go that route, you can shorten your code to this:
return allFoos.All(foo => foo.FooVar1 == defaultFoo.FooVar1);
I'm not quite sure what the question is, but if you're looking for some way to unify the IsFoorVarXConsistent code, you could do it using reflection or by passing in an expression:
public bool IsConsistent(Func<Foo, bool> property)
{
foreach (Foo tempFoo in allFoos)
{
if (property(tempFoo) != property(defaultFoo))
return false;
}
return true;
}
Called like this:
bool is1Consistent = IsConsistent(f => f.FooVar1);
As shown this will only work for boolean properties. To extend it to other types, we can make it generic in the property type. However, in this case we cannot use != to test for inequality because not all types define a != operator. Instead we can use the .Equals method and the ! operator:
public bool IsConsistent<T>(Func<Foo, T> property)
where T : struct
{
foreach (Foo tempFoo in allFoos)
{
if (!property(tempFoo).Equals(property(defaultFoo)))
return false;
}
return true;
}
The where T : struct clause restricts this to value types like int, bool and decimal. In particular it will not work on strings. Removing the where constraint allows it to work on strings and other reference types, but creates the possibility of property(tempFoo) being null, which would cause a NullReferenceException when we called .Equals on it. So if you remove the value types constraint then you will need to add error handling for this scenario.

LINQ, entity that implements Interface and exception in mapping

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
{
}

Categories