Let's say I have an Entity Object 'Jewels' that has the properties 'Name' and 'Birthdate'.
I want to implement a LINQ query that returns an object that has 'Name', 'Birthdate' and 'Birthstone'. So I extend 'Jewels' like this:
public partial class JewelStones : Jewels
string Birthstone = null;
public void JewelsWithStone()
{
this.Birthstone = "diamond";
//(we figure out what stone applies to the month here)
}
I can get this far, and I THINK I'm on the right track, but I don't know how to write a LINQ query and get back an object that includes Birthstone, so I can bind that object to a grid that will show Birthstone, which I'm not storing anywhere, as it's always calculated (this is pretend data, sorry if it's not logical).
List<Jewel> jewels = new List<Jewel>;
using (jewelentities db = new jewelentities())
{
jewels = (from j in db.Jewels select j).ToList();
}
How do I fill up my JewelStone object with Name, Birthdate, and Birthstone?
If I'm not following best practice here, please let me know!
EDIT
I've tried adding a partial class to the Entity partial class. When I reference the Jewel class now, it 'sees' the Birthstone property, but it is null. I don't know why? Here is the partial class:
public partial class Jewel
{
private string _birthstone;
public string Birthstone
{
get { return _birthstone; }
set
{
JewelBusiness jewelBusiness = new JewelBusiness();
_birthstone = jewelBusiness.RequestBirthstone(birthmonth);
}
}
}
If I use LINQ to query the entity to get a list of Jewel records, I get all the info from the Entity, Jewel.Birthstone is there, but it is null. However if I do a foreach on the results ---
foreach (Jewel j in jewels)
{
string stone = jewelBusiness.RequestBirthstone(j.Birthmonth);
}
stone will equal the expected result (birthstone for that month).
Why doesn't my partial class return the birthstone??
I'm not sure I understand your requirement correctly. But if you don't want to store Birthstone but calculate it on the fly, just change your code to
public partial class Jewel
{
private string _birthstone;
public string Birthstone
{
get
{
if (_birthstone == null)
{
JewelBusiness jewelBusiness = new JewelBusiness();
_birthstone = jewelBusiness.RequestBirthstone(birthmonth);
}
return _birthstone;
}
}
}
Isn't your Jewels EntityObject in a partial class too? You can most likely just add a Jewels partial class to "extend" it and add the wanted property there.
For me, it depends on where the logic for the calculated column resides.
If it resides in database, then you must do join query in the Linq. I assume in this case, you has a table named BirthStoneTable, with the month as the relation. I don't suggest to add a ternary operation inside linq query, such as select j.BirthDate.Month == 1 ? "Diamond" : //etc etc. It is hard to debug and to track (moreover for code coverage reason).
If it resides in UI specific (only to improve the display), I usually add a type-casted class, such as:
public class JewelUI{
public explicit operator JewelUI(Jewel jewel){
JewelUI jewelUI = new JewelUI();
// assign birthdate and name
jewelUI.BirthStone = GetBirthStone(jewel.BirthDate.Month);
}
public string BirthStone{get;set;};
public string GetBirthStone(int month){
if(month == 1) return "Diamond";
//etc etc
}
}
If the calculated column is used in the business logic, usually I handle the calculation in service / business logic. All of it to ensure the good Separation of Concern.
NB: I may misunderstand your requirement though
Related
I'm a beginner with EntityFramework and WCF, so I don't yet know how everything works, so I'll try to explain my situation as best as I can..
I have WCF service that uses a database with EntityFramework and I have managed to get it to work just fine for example like this:
using (var entities = new databaseEntities())
{
// Check if there is 0 rows, then just add the new row.
int count = entities.Table1.Where(i => i.Name == name).Count();
if (count < 1)
{
var newEntry = new Table1
{
Name = name,
InsertDate = DateTime.Now,
CreatedBy = createdBy,
Comment = comment,
Active = true
};
entities.Table1.Add(newEntry);
entities.SaveChanges();
}
}
The problem arrives when I have more than one table and I want to decide which one to use. The tables are basically the same and thus would use the same operations, so I would like to use one function for all of them (that way I can avoid duplicate code). But I can't seem to understand how I can change the table at runtime for example via a switch/case.
For Example:
// A function that gets the type of the table I want to access
void WriteToSomeTable(int type)
{
switch (type)
{
case 0:
//The table to update is Table1
break;
case 1:
//The table to update is Table2
break;
}
}
If I want to get the count of all the entries with a given name with
int count = entities.Table1.Where(i => i.Name == "somename").Count();
how can I make the "entities.Table1" determined at runtime?
I can make variables:
System.Data.Entity.DbSet<Table1> firstTable = entities.Table1;
System.Data.Entity.DbSet<Table2> secondTable = entities.Table2;
So I thought that with a list i could set an int index; to a different value with the switch/case and then just use
int count = list[index].Where(i => i.Name == "somename").Count();
but I can't add them to a List, since they are different types
// entity.Table1 is
System.Data.Entity.DbSet<Table1>
// and entity.Table2 is
System.Data.Entity.DbSet<Table2>
ArrayList won't cut it either, since there are no ".Where" function if i try to use the objects inside the ArrayList.
I also tried with just the System.Data.Entity.Dbset, but to use the ".Where" function, I would need to use .Cast() function, but I cant store the needed "TEntity" to a variable (or can I?). For Example:
System.Data.Entity.DbSet firstTable = entity.Table1
Type t = firstTable.GetType();
int count = firstTable.Cast<t>().Where(i => i.Name == "somename").Count();//doesn't work
//This, however works:
int count = firstTable.Cast<Table1>().Where(i => i.Name == "somename").Count();
I hope I made some sense on what my problem here is :) Hopefully someone has an idea, how to solve this, since I have battled with this for ages now, and the only solution I have come up with is to have a separate function call in each switch/case with the exact same code, except for the "entity.Table" part. And having to write the same set of code multiple times isn't a very good solution :(
Make generic function...
public void MyAddFunction<T>(T newItem, databaseEntities db,
Expression<Func<T, bool>> predicate) where T : class
{
var table = db.Set<T>();
int count = table.Count(predicate);
if(count < 1)
{
table.Add(newItem);
}
db.SaveChanges();
}
and according to your cases call your function(You want to add table1 for example)
using(var entities = new databaseEntities())
{
MyAddFunction<Table1>(new Table1(), entities , x => x.Name == "name");
}
You don't say so, but since you are working with Entity Framework, I assume that your class databaseEntities is the DbContext that contains all your Entities as DbSet<TEntity> properties.
You write that your problem is that you know the type of the entities (in my exaple TEntity), but you don't know how to get the corresponding DbSet. Your proposal is to use a switch statement for this.
Luckily this is not needed. DbContext.Set(Type) does this for you. You provide the Type, Dbcontext returns the DbSet of this type.
public class SchoolContext : DbContext
{
public DbSet<Student> Students {get; set;}
public DbSet<Teacher> Teachers {get; set;}
public DbSet<ClassRoom> ClassRooms {get; set;}
...
}
If you know the type already at compile time, use DbContext.Set<TEntity>, if TEntity is only known at runtime, use DbContext.Set(Type entityType)`
Type entityType = ...;
DbSet mySet = DbContext.Set(entityType);
The problem is of course, that at compile time you don't know the entityType, and thus don't know what functions you can call and what properties your entityType has.
If you are certain that your entities has certain properties, like in your example property Name, consider deriving all your entities from a common interface. Like this:
interface ICommonSchoolProperties
{
public int Id {get;} // primary key
public string Name {get;}
}
public class Teacher : ICommonSchoolProperties {...}
public class ClassRoom : ICommonSchoolProperties {...}
etc.
Now you are certain, that whenever you ask the SchoolContext for an item of any type, you are certain that the items you get have at least an Id and a Name. And thus you can do the following:
Type entityType = ...
IEnumerable<ICommonSchoolProperties> schoolItems = mySchoolContext
.Set(entityType)
.Cast<ICommonSchoolProperties>)();
And you can call the functions of which you are certain that your SchoolProperty has.
var nrOfItems = schoolItems
.Where(schoolItem => schoolItem.Name = ...)
.Count();
var allKnownNames = schoolItems
.Select(schoolItem => schoolItem.Name)
.Distinct();
The problem remains if you want to call functions that Teachers have, but ClassRooms have not.
This is a fairly rare case, and if you have an object of which you don't know what functions it has, you should reconsider your design and think about creating functions that handle these objects, instead of giving the type, decoding what functions this object has and then use them
Instead of:
private void WriteToSomeTable(Type type)
{
if type is a teacher
call teacher functions
else if type is classroom
call classroomfunctions
else
DoSomeThingcommon(...)
}
Consider:
public void WriteTeacherTable()
{
call teacher functions();
DoSomethingCommon();
}
private void WriteClassRoomtable()
{
call classroom functions;
DoSomethingCommon();
}
Note that the number of lines hardly increase.
Somewhere inside your program there is a place where you know that you are dealing with Teachers instead of ClassRooms. The only reason in a proper OO design where you would mix Teachers and ClassRooms as if they were something similar would be if you know you only want to call the functions they have in common. If that is the case, go back to the interface function where you know which common functions you can call.
I want to provide predefined filters for displaying search results. The filter is more or less stored as an expression tree and can be constructed using a rule editor.
I want to provide the user with an editor, select a property, select the operator and allow the user to provide or select a value to compare with.
[dropdown with properties = PriorityId] [dropdown with operators = Equals] [dropdown with values = IList()]
The challenge is that the user needs to get a list of values to select from and I am figuring out how to
I have thought about the following approach, and I would like to get your input on this.
Decorate the property with an attribute
The attribute maps a class responsible for returning possible values
The mapping class implements an interface
When selecting the property from the rule editor I can execute an ajax call to a supporting controller to get the values back. In this controller I can invoke the mapping class via reflection to return the values.
namespace Tickets.Data.Model
{
public class Ticket : BaseModel
{
[RuleEditorCollectionMapping(typeof(GetPriorities))]
public string PriorityId { get; set; }
}
}
public class RuleEditorCollectionMappingAttribute : Attribute
{
private Type classType;
public RuleEditorCollectionMappingAttribute(Type classType)
{
this.classType = classType;
}
}
public interface IRuleEditorCollectionMapping{}
public class GetPriorities : IRuleEditorCollectionMapping
{
public static IList<TicketPriority> GetValues()
{
// query logic to build a list with values to be used in the rules editor when selecting PriorityId
return new List<TicketPriority>();
}
}
Questions:
Is my approach a viable one? More or less a sanity check so I don't take the wrong turn.
If not, do you have any other suggestions or guidance from experience to approach this situation?
I am trying to replace a nasty LINQ 2 SQL hit with some dapper queries to improve performanace. In doing so I have to weave a bunch of different objects together in order to create the big object required to hold all the information I need for ASN information.
The current problem I am having is with an abstract class Orders, this class is implemented by two seperate classes AutionOrder and MerchantOrder using a discriminator property.
Since I cannot use dapper to create a object that is an abstract class I am instead using one of the public classes. however when it goes to build the object it is failing inside of GetSettableProps it is finding the proper DeclaringType but the GetProperty method is returning null when it is looking for an property that is internal or is an EntitySet. I've tried to hack around it using t.BaseType.GetProperty as well as p.GetAccessors().First().GetBaseDefinition().DeclaringType.GetProperty(p.Name).GetSetMethod(true) with no success.
dummy objects:
Order
OrderID, Name, Address, RowVersion(internal), Shipments(EntitySet),OrderDetails(EntitySet), Customer(EntityRef)
Shipment
ShipmentID, OrderID, TrackingNumber
OrderDetails
OrderDetailID, OrderID, Product, QTY, Price
Customer
CustomerID, Name,
For this particular SQL hit I am trying to grab some of the 1 to 1 relationship mappings I need.
SELECT o.* from Orders as o left join Customers as c on o.CustomerID = c.CustomerID where o.OrderID in (1,2,3);
This is what I am using to utilize dapper and let it do it's magic:
using (var connection = new SqlConnection(_ConnectionString))
{
connection.Open();
results = connection.Query<MerchantOrder, MerchantCustomer, MerchantOrder>(sql.ToString(),
(o, c) => { o.Customer = c; return o; },
splitOn: "CustomerID");
}
If I change Order to be a public class this problem goes away though, but this is not a desired side-effect. It is failing when trying to set the propInfo for RowVersion - switching this to public instead of internal solved this problem - although not desired. But then it fails when it is trying to create the Shipments objects for Order. Again none of this is an issue when Order is a public class.
Also I am doing separate queries to pull in Many to one relationships such as Shipments to Orders and OrderDetails to Orders and normalizing the results into a proper Order Object.
MerchantOrder is pretty much an empty class with no real special logic. The discriminating different here is just how we end up finding the CustomerID which is abstracted away prior to the actual SQL hit anyway.
Also I am using the latest version of dapper as of 12/20/2011.
I really like dapper, but this problem is making my head asplode - so thanks for the help!
This was a bug, that is now fixed in trunk:
public class AbstractInheritance
{
public abstract class Order
{
internal int Internal { get; set; }
protected int Protected { get; set; }
public int Public { get; set; }
public int ProtectedVal { get { return Protected; } }
}
public class ConcreteOrder : Order
{
public int Concrete { get; set; }
}
}
// http://stackoverflow.com/q/8593871
public void TestAbstractInheritance()
{
var order = connection.Query<AbstractInheritance.ConcreteOrder>("select 1 Internal,2 Protected,3 [Public],4 Concrete").First();
order.Internal.IsEqualTo(1);
order.ProtectedVal.IsEqualTo(2);
order.Public.IsEqualTo(3);
order.Concrete.IsEqualTo(4);
}
One side note is that, by design, we do not set private fields or properties in the base classes. The behaviour can be magical and not consistent.
Eg:
class A { private int a {get; set;} }
class B : A { private int a {get; set;} }
class C: B {}
// What should "select 1 a" do? Set it on A? Set it on B? Set it on Both? Set it on neither?
We went with "set it on neither"
I think is not possible (because of the abstract class) without modifying your code.
I had a similar problem and ended up creating a new object private to the assembly where I have my repositories that derived from the abstract base class.
This class is not abstract and only visible to the repository class that stores the data, this class had all the required methods for the actual table.
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);
}
My Title may be slightly off but here is what I am trying to do. I have a L2S Method that would be for every table that I would like to write once. This is to set a soft lock column where I will also need a Read and UnLock method. Here is what I have so far:
public static void LockRow(string TableName, int TablePrimaryKey)
{
using (var context = McpDataContext.Create())
{
var tableToLock = (from lockTable in context.tblPlans
where lockTable.PlanID == TablePrimaryKey
select lockTable).Single();
tableToLock.Locked = true;
context.SubmitChanges();
}
}
What I would like to do is replace context.tblPlans with context.TableName. Is this possible in LINQ? How so? I am assumming that I am going about it the wrong way so I'd be grateful for some direction/pointers.
Thanks
Update becuase the first example would not work.
You could do it with a generic method and an interface:
public interface IPlanTable
{
int PlanID { get; set; }
}
public static void LockRow<TEntity>(int TablePrimaryKey) where TEntity : class, IPlanTable
{
using (var context = McpDataContext.Create())
{
var tableToLock = (from lockTable in context.GetTable<TEntity>()
where lockTable.PlanID == TablePrimaryKey
select lockTable).Single();
tableToLock.Locked = true;
context.SubmitChanges();
}
}
You will also have to use the fact that the Linw2SQL tables are created as partial classes to extend them so all the relevent table implement IPlanTable
You would use it like below:
LockRow<tblPlan>(23);
simply replace tblPlan with whatever the name of your table class is.
However this won't allow you to set the table at runtime, LinqToSQL is object orientated and type safe, specifying the table you want to retreive is contrary to how it si designed to work.