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);
}
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.
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
Basically, I would like to create a Method, that takes a base-class as a parameter, and can be used "generic" for derived classes
ef-code-first classes:
the base class
public abstract class BaseClass
{
public int Id { get; set; }
public string Name { get; set; }
}
derived classes:
public class DerivedA:BaseClass
{
public string AValue {get;set;}
...more specific fields
}
public class DerivedB:BaseClass
{
public string BValue {get;set;}
..... more specific fields
}
I call a "generic Method" with these slightly different objects:
System.Data.Entity.DbSet<DerivedA> _dA....
System.Data.Entity.DbSet<DerivedB> _dB....
genericMethod(_dA.Where(a => a.Name.StartsWith("a name")))); //<-contains records
genericMethod(_dB.Where(a => a.Id==5)); //<---- contains records
Both "Where..." contain records in debug (after clicking on Enumerate)
now the method:
public string genericMethod(<IQueryable>BaseClass _myClass)
{
foreach (BaseClass c in _myClass) // <-------class is empty - no records
{
// do something usefull...
}
return someResult
}
But no records are contained, when inside the method.
Is it possible, what I am trying to do...?
Does it make sense?
There are no design-time or compile-time or runtime errors, but the passed object contains no records when passed to the method, but it contained records in the calling statement.
What did I do wrong?
Is there a better approach? -
I need this Method, for manipulation of more than two (maybe ten) derived classes, and therefor I want it "generic".
Thank you!
When faced with something like this, I like to simplify my code.
I would try removing the _dA.Where(a => a.Name.StartsWith("a name")) and _dB.Where(a => a.Id==5) from the method call and put them into variables first (and then pass the variable into the method).
This will allow you to better inspect your code and perhaps shed light on the problem.
add .ToList() to materialize the query before you pass it to the method:
genericMethod(_dA.Where(a => a.Name.StartsWith("a name"))).ToList());
Otherwise you're not really passing the result of the query, you're just passing a query that needs to be evaluated first. ToList() will evaluate it for you. When you look in the debugger watch, it's basically evaluating it for you on the fly, that's why you see rows returned.
After that, change your method to deal with IList instead of IQueryable.
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.
Let's say I need to display a list of customers, but only want to display the Name and somehow associate the key to the name within a list control.
It would probably be costly to retrieve the entire list of customers and all it's properties. In this scenario, would it be better to create another class with the properties that are required (in this case Id and Name)?
A basic implementation could look like this:
public class Customer {
public int Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public int Age { get; set; }
.....
}
public class CustomerListView {
public int Id { get; set; }
public string Name { get; set; }
}
public interface IRepository<T> {
public T Find(int id);
public IEnumerable<T> FindAll();
....
}
public class Repository<T>: IRepository<T> {
....
}
public class CustomerRepository: Repository<Customer> {
public IEnumerable<CustomerListView> FindAllListView();
}
Would this approach be appropriate? What other options would there be?
In order to achieve such goals, I create a simple 'View' class, for example CustomerView, which just contains the properties that are needed to display an overview.
My Repository then has a method which returns a collection of these CustomerView objects.
I mostly use NHibernate in my projects. Nhibernate allows you to use 'projections'.
So, what I do in my repository is this:
(note that the code below is just some pseudo-code; it won't compile).
public IList<CustomerView> GetAllCustomers()
{
ICriteria crit = _session.CreateCriteria (typeof(Customer));
crit.AddProjection ( ... );
crit.SetResultTransformer (new EntityToBeanTransformer(typeof(CustomerView));
return crit.ToList();
}
In fact, it comes down to this: I tell my O/R mapper that it should query Customers, but that it should return entities of type 'CustomerView'.
In the defintion of the projection, I also define which properties of the Customer class map to which properties of the CustomerView class.
Then, the O/R mapper is smart enough to generate a very simple query, which only retrieves those fields that are required to populate the CustomerView class.
For instance, the query that is executed can be as simple as:
SELECT customerid, customername FROM tblCustomer
If you use IQueryable as your return instead of IEnumerable than there is no cost of doing:
CustomerRepository().GetAll().Find(1) because AsQueryable doesn't actually execute until you request data. That means LINQ can optimize it out to a:
SELECT .... FROM .... WHERE ID = 1 instead of
GET EVERYTHING. FIND WHERE THE ID = 1
See this post for an explanation:
Why use AsQueryable() instead of List()?
Using this approach you could create an anonymous class and futher narrow down the data going over the wire to just what you want. That way the query generated by LINQ is optimized to the fullest.
If you have to retrieve the list form a Database then your proposal makes some sense but I would look into a Linq and anonymous type solution.
If the list of Customers already exists in memory then there there are no savings.
You could combine the techniques used by Nissan and Frederik (anonymous types and NHibernate) by using Linq-to-NHibernate.
Item #31 in Bill Wagner's More Effective C# says "limit type scope by using anonymous types", and I agree. BTW, I recommend the whole book.