c# Linq to Sql dynamic Data Context assignment - c#

`Hi,
Can somebody please give me a pointer on this? I have 8 servers each with 8 databases which look identical exept server/database name. We are talking thousands of tables.
I create my data contexts with sqlmetal.exe
After creating my data contexts, I import them into the application and then I run comparison scripts over the databases to compare results.
My problem is dynamically switching between data contexts.
Datacontext.DAL.DUK1 duk1sdi = new Datacontext.DAL.DUK1(connectionString);
Datacontext.DAL.DUK3 duk3sdi = new Datacontext.DAL.DUK3(connectionString);
string fromOne = runQuery(duk1sdi);
string fromThree = runQuery(duk3sdi);
public static string runQuery(DataContext duk)
{
var query =
from result in duk.TableA
select result.Total;
string returnString = query;
return returnString;
}
I have no problem with the query running when the duk is predefined, however how do I define and pass the datacontext to the function?
The error I get is:
Error 1 'System.Data.Linq.DataContext' does not contain a definition
for 'TableA' and no extension method 'TableA' accepting a first
argument of type 'System.Data.Linq.DataContext' could be found (are
you missing a using directive or an assembly reference?)

You could use the GetTable<T> method, where T is the type of the table, e.g. TableA.
public static string runQuery(DataContext duk) {
var table = duk.GetTable<TableA>();
var query = from result in table select result.Total;
...
}
However, all types of TableA will need to be the same type, strictly (I'm pretty sure).
Otherwise you would need to literally branch the logic for the handling of each context. Since you can extend your DataContext instances (in general, maybe not in your specific case) then you could have them share an interface that exposes a collection property of TableA, but you would need a higher level context wrapper to pass around then - unless you pass around the collection by altering the method signature.

You can use interfaces. Check this answer, but be sure to script the interfaces using a .tt file with the amount of tables you have.
Edit:
If you have generated contexts which you want to use interchangeably in a reusable method, you have the problem that the generated TableA classes are not reusable, since they are different types (even though the names may match, but that doesn't make them equal). Therefore you need to abstract the actual types, and one way to do this, is to use interfaces. You build your reusable method around an interface which abstracts the specific context-type and table-type. The downside is that you have to implement the interfaces on the generated contexts and tabletypes. This though is something you can solve using a .tt script.
Pseudo code:
// Define interface for table
public interface ITableA {
// ... properties
}
// Define interface for context
public interface IMyContext {
IQueryable<ITableA> TableA { get; }
}
// Extend TableA from DUK1
public partial class TableA: ITableA {
}
// Extend DUK1
public partial class Datacontext.DAL.DUK1: IMyContext {
IQueryable<ITableA> IMyContext.TableA {
get { return TableA; }
}
}
// Same for DUK3 and TableA FROM DUK3
// Finally, your code
Datacontext.DAL.DUK1 duk1sdi = new Datacontext.DAL.DUK1(connectionString);
Datacontext.DAL.DUK3 duk3sdi = new Datacontext.DAL.DUK3(connectionString);
string fromOne = runQuery(duk1sdi);
string fromThree = runQuery(duk3sdi);
public static string runQuery(IMyContext duk) {
// Note: method accepts interface, not specific context type
var query = from result in duk.TableA
select result.Total;
string returnString = query;
return returnString;
}

If your schema is identical between databases, why script the dbml for all of them? Just create one context with it's associated classes and dynamically switch out the connection string when instantiating the context.
var duk1sdi = new Datacontext.DAL.DUK1(connectionString1);
var duk3sdi = new Datacontext.DAL.DUK1(connectionString2);

Thanks, guys, I think I found the simplist solution for me based a bit of both your answers and by RTFM (Programming Microsoft Linq in Microsoft .NET Framework 4 by Paulo Pialorsi and Marco Russo)
In this way I don't have to use the large DBML files. It is a shame because I'm going to have to create hundreds of tables in this way, but I can now switch between connection strings on the fly.
First I create the table structure. (outside the program code block)
[Table(Name = "TableA")]
public class TableA
{
[Column] public int result;
}
Then I define the table for use:
Table<TableA> TableA = dc.GetTable<TableA>();
And then I can query from it:
var query =
from result in TableA
select TableA.result;

Related

How to pass variable entities to a generic function?

If i generate my entities through Entity Framework Database First, and i want to use a function like that:
AuditManager.DefaultConfiguration.Exclude<T>();
considering that the number of times i want to call it should be equal to the number of entities
ex:
AuditManager.DefaultConfiguration.Exclude<Employee>();
AuditManager.DefaultConfiguration.Exclude<Department>();
AuditManager.DefaultConfiguration.Exclude<Room>();
Now how to Loop through selected number of entities and pass every one to the Exclude function ?
The obvious solution would be to call the method for every entity-type you want to hide. Like this:
AuditManager.DefaultConfiguration.Exclude<Employee>();
AuditManager.DefaultConfiguration.Exclude<Department>();
AuditManager.DefaultConfiguration.Exclude<Room>();
You can add conditional statements (ifs) around them to do it dynamically.
Howevery, if you want a fully flexible solution, where you call the Exclude method based on metadata, you need something else. Something like this:
var types = new[] { typeof(Employee), typeof(Department), typeof(Room) };
var instance = AuditManager.DefaultConfiguration;
var openGenericMethod = instance.GetType().GetMethod("Exclude");
foreach (var #type in types)
{
var closedGenericMethod = openGenericMethod.MakeGenericMethod(#type);
closedGenericMethod.Invoke(instance, null);
}
This assumes that the Exclude<T> method is an instance method on whatever instance DefaultConfiguration points to.
An alternative to looping through your entity types is to make the entities you don't want audited implement the same interface and exclude that. For example:
public interface IExcludeFromAudit
{ }
And your entities:
public class Order : IExcludeFromAudit
{
//snip
}
And now just exclude the interface:
AuditManager.DefaultConfiguration.Exclude<IExcludeFromAudit>();
The benefit of this is that it's now easy to control which ones are excluded.

PetaPOCO and more than 4 joins

Is petapoco capable of achieving the following :
1.Unlimited joins in one query
2.Unlimited One to Many relations in one query
I have looked at PetaPOCO and it seems like it is not capable of doing more than 4 joins, the longest signature looks like :
db.Query<T1, T2, T3 , T4>
Also seems like it supports a one to many relation , but only for one composite object such as below :
db.FetchOneToMany<T1, T2> where T2 is a foreign key of T1
I'm testing some of the micro ORMs out there to stick to the best one. Do you know of any of them that can handle these situations and if none of the micro ORMs are supporting this feauture, how do you deal with an object that is like the following :
class A
{
List<B> member1;
List<C> member2;
Z member3; //Composit object
Z1 member4; //Composit object
Z2 member5; //Composit object
Z3 member6; //Composit object
Z4 member7; //Composit object
}
And then even more complicated is , what if member one (type B) has some composite object within itself ? What if we have :
class B
{
G member0;
}
Please don't propose a solution to hit database multiple times, coz it's going to be way too many calls when the objects become just a little bit complex.
Oh and i also know that one other way of tackling the case of unlimited joins is creating a very flat object that hols all fields combined. It's not an elegant solution at all.
The T1..T$ Query() overloads all pass through to the main Query(..Type[]..) method. You can either add more Query() overloads yourself to handle more T parameters, or pass in all the types you need in a Type array (which is what the T1-T4 functions do) :
Query<TRet>( new Type[]{typeof(Poco1), typeof(Poco2), typeof(Poco3), typeof(Poco4), typeof(Poco5)}, null, sql, args);
You can have multiple one to many relationships but Schotime is right, you need to be very careful of swathes of duplicate data coming back in your result set. Write the sql query and look at the result set, is the amount of duplication acceptable to you? If so then in Petapoco there is a concept of relator callbacks where you write a small class that handles the different pocos in a single result row and add each poco to the list properties on the parent poco.
http://www.toptensoftware.com/Articles/115/PetaPoco-Mapping-One-to-Many-and-Many-to-One-Relationships
I've never had to do this with multiple one to many but quoted from the above
"If you're joining more than two tables you'll need something more
complex but it's really just extensions of the above."
Another option is to have a stored procedure that does all the work in a single database request and have it return multiple result sets which I believe Schotime has achieved in his branch of petapoco but I've not used it myself yet so I can't really comment on if it will help here :
http://schotime.net/blog/index.php/2011/11/20/petapoco-multiple-result-sets/
If I absolutely had to wire up all the data in one go for objects as complex and nested as you are suggesting then I would use a stored procedure (a single db call) and stitch it all together with code. Only then would I figure out how to do this in Petapoco. However if your UI doesn't show all the nested data until the user clicks on an expander button (or similar) I'd use an AJAX call at that point rather than get all the data initially.
The answer is correct, but I came to this page from another forum and no one there could make this work, so I thought I would chip in what I did to make things clearer. Basically, I had code like the following:
var sql = "select * from someTable where tableId = #0";
var listOfStuff = _petapoco.Fetch<FirstType, SecondType, ThirdType, FourthType, FirstType>(new RelatorClass().MapIt, sql, idVar);
Since I needed to add in a fifth poco, and all the Fetch methods eventually lead to the master Query method listed above in the accepted answer, I had to do this:
var sql = "select * from someTable where tableId = #0";
Func<FirstType, SecondType, ThirdType, FourthType, FifthType, FirstType> mapIt = new RelatorClass().MapIt;
var listOfStuff = _petapoco.Query<FirstType>(new[] { typeof (FirstType), typeof (SecondType), typeof (ThirdType), typeof (FourthType), typeof(FifthType)}, mapIt, sql, idVar).ToList();
Now I can query with 5 pocos and I didn't have to modify the PetaPoco code. The only other thing to do would be to add to your relator class so you can tell PetaPoco where to map the new data and you're good to go.
Delegate:
Note: you don't have to return the (UserActivity,int) anonymous type like this, you can return a single type without the parenthesis! I'm just lazy and don't want to create a new model for the return type.
private delegate (UserActivity, int) GetIt(int fk_AccountTypeValue, UserActivityModel ua, User u, Client c, Client_Account ca);
SQL Operation:
public List<(UserActivity,int)> SomeMethodName(int orgnizationID)
{
var sql = Sql.Builder
.Select("TOP(200) at.FK_AccountTypeValue, ua.*, u.*, c.*, ca.*")
.From("UserActivity ua")
.LeftJoin("Users u").On("u.PK_UserID = ua.FK_UserID")
.LeftJoin("Client c").On("c.FK_UserID = u.PK_UserID")
.LeftJoin("Client_Account ca").On("ca.FK_ClientID = c.PK_ClientID")
.LeftJoin("AccountType at").On("at.PK_AccountType = c.FK_AccountTypeID")
.Where("u.FK_OrganizationID =#0", orgnizationID)
.OrderBy("ua.Timestamp desc");
GetIt obj = new GetIt(youKnowIt);
var typs = new Type[]{typeof(int), typeof(UserActivityModel), typeof(User), typeof(Client), typeof(Client_Account)};
var uaList = _database.Query<(UserActivity, int)>(typs, obj, sql.SQL, sql.Arguments).ToList();
return uaList;
}
Method pointed to by the delegate:
private (UserActivity,int) youKnowIt(int fk_AccountTypeValue, UserActivityModel ua, CurrentDesk.Models.User u, CurrentDesk.Models.Client c, CurrentDesk.Models.Client_Account ca)
{
// do stuff
var uam = new UserActivity()
{
// assign stuff
};
return (uam, fk_AccountTypeValue);
}

How to create a generic method out of two similar yet different methods?

I have two similar methods that basically does the same thing only with different objects.
What's the best way to make a generic method out of this if possible?
The two objects:
public class StoreObject {
int Key;
string Address;
string Country;
int Latitude;
int Longitude;
}
public class ProjectObject {
int ProjectKey;
string Address;
string Description;
}
The two methods that I potentially want to make into a generic:
public StoreObject GetStoreByKey(int key)
{
using (DBEntities dbe = new DBEntities())
{
StoreObject so = new StoreObject();
var storeObject = (from s in dbe.StoreTables
where s.Key == key
select s).First();
so.Key = storeObject.key;
so.Address = storeObject.address;
so.Country = storeObject.country;
so.Latitude = storeObject.latitude;
so.Longitude = storeObject.longitude;
return so;
}
}
public ProjectObject GetProjectByKey(int projectKey)
{
using (DBEntities dbe = new DBEntities())
{
ProjectObject po = new ProjectObject();
var projectObject = (from p in dbe.ProjectTables
where p.ProjectKey == projectKey
select p).First();
po.Key = projectObject.p_key;
po.Address = projectObject.p_address;
po.Description = projectObject.p_description;
return po;
}
}
I must note that:
- I have no control over how the table fields are named (ie. p_description).
- StoreTable in the DB, for example, may have other properties (like telephone, postal code, etc) but I'm only interested in showing what I've shown in the code.
- The same goes for the ProjectTable.
Well, the tricky part is that your entities have different properties, so using generics to populate the different properties within one method will not be worth it. But you can return the whole object and then just use the properties you are interested in.
public T GetEntityByKey<T>(int key)
{
using (DBEntities dbe = new DBEntities())
{
return = dbe.StoreTables.Set<T>.Find(new object[] {key});
}
}
And to use it
StoreObject so = GetEntityByKey<StoreObject>(123);
if(so != null)
{
int lat = so.Latitude;
}
You can indeed abstract out the type returned, and factor the using, but for the rest you'd need either a switch on the type requested or, reflection to pass in the fields to retrieve as parameters and the DB query to use.
The former would be bad practice and brings little to the equation, and the latter is costly and can get messy.
This is not really a good candidate for generics, unless you have many of such look-alike methods, in which case I'd go for the reflection approach.
HTH,
Bab.
It's very unlikely that this is your entire 'unit of work' and thus the use of a fresh DBEntities() context in each of these methods is probably the root of your problem here.
Creating a Repository class that includes an instance of the DBEntities class for a single web request (or whatever other unit of request you have in your application) and which has these methods in it would be a better approach to eliminating the duplicate code here. The scope of the using() is then outside these methods and hopefully tied to your web request or other unit of time.
As an option instead of creating a new class you could also extend the DBEntities partial class to include methods like these (assuming this is generated code).
You essentially have two different functionalities in each method:
Query an entity
Map that entity to another type
The first part has been addressed by Steve Mallory.
For the second part, you can use a mapper framework to handle copying values from one instance to another. Since the names of each type do not match, you'll need to tell it how to map names (in your example, adding "p_" and making it lowercase). One possibility would be Emit Mapper.
If you were to factor out all commonality, it would be something like:
public TResult GetById<TResult, TEntity>(int id)
{
using (DBEntities dbe = new DBEntities())
{
T result = dbe.StoreTables.Set<T>.Find(new object[] {key});
var mapper = ObjectMapperManager.DefaultInstance
.GetMapper<TEntity, TResult>(
new DefaultMapConfig().MatchMembers((m1, m2) => "p_" + m1.ToLower() == m2));
return mapper.Map(result);
}
}

How to use a c# method in a sql stored procedure

I wanted to use linq as so:
MyDBEntities context = new MyDBEntities();
context.MyTable.Where(i => MyMethod(i.column, valueToTest).ToList();
with
public bool MyMethod(Object a, Object b)
but apparently using such a method with isn't possible
so I was hopping I could use the methode in a stored procedure I would be able to call with linq
do you think is it possible ?
Generally it is possible to create C# function and use it in SQL Server (2005 and newer) but it is not so simple - you must use SQL CLR which means separate project for your function, special references, special types, etc. At last you must deploy the assembly to SQL server to be able to use the function in SQL. General documentation also covering how to create custom function:
Creating SQL Server Objects in Managed Code
Once you have your function on SQL server you can use it within stored procedure and you can use it within query. I'm actually not sure if you can import these functions into Linq-to-sql or EF model and use them in Linq-to-sql or Linq-to-entities queries.
Take a look here for a complete sample:
Calling custom methods in LINQ-to-SQL
I hope I understand you correctly.
Let's say that MyTable is a database table that contains the columns Name, and Address
Here's how you would get a value back whether the results contain the specified value you passed.
public void SomeMethod()
{
MyTable table= new MyTable();
bool b= MyMethod(table.Name, "Fred");
if(b)
//Do something
else
//Do something else
}
public bool MyMethod(MyTable a, object value)
{
using(var context= new MyDBEntities())
{
return context.MyTable.Where(i => a == value).Any();
}
}
This is what the database table 'MyTable' looks like behind the scenes.(the data context generated this)
public class MyTable
{
public string Name { get; set; }
public string Address { get; set; }
}
So you can see in the first method I pass table.Name to MyMethod, that's only possible because MyTable has a pubic property called Name. Also notice that we are using type Object for the value, as the parameter could an int, a string, a date time, who knows.
Note: This is untested code, but should get off to right track if I understand you correctly.

Deep Reflection in .NET

I need to create the ability to drill through an objects properties like two or three deep. For instance, class A has a property reference to class B, which I need to access class C. What is the best way to do this: straight reflection, or maybe using the TypeDescriptor, or something else?
Thanks.
It's not too hard to write. I put a few classes together to deal with this so I could serialize properties of a WinForm. Take a look at this class and the related classes.
http://csharptest.net/browse/src/Library/Reflection/PropertySerializer.cs
If you know the path in a static context (ie the path is always the same) and the properties are accessible (internal or public) you can use dynamic
[Test]
public void Foo()
{
var a = new A
{
B = new B
{
C = new C
{
Name = "hello"
}
}
};
DoReflection(a);
}
private void DoReflection(dynamic value)
{
string message = value.B.C.Name;
Debug.WriteLine(message);
}
I you wanna write you own serialization code for whatever reason, you'll be using reflection.
What you do is that you write a recursive method of serlizating a type. You then apply this as you see fit to get the result.
var type = myObjectOfSomeType.GetType();
// now depending on what you want to store
// I'll save all public properties
var properties = type.GetProperties(); // get all public properties
foreach(var p in properties)
{
var value = p.GetValue(myObjectOfSomeType, null);
Writevalue(p.Name, value);
}
The implementation of WriteValue have to recognize the built in types and treat them accordingly, that's typical things like string, char, integer, double, DateTime etc.
If it encounters a sequence or collection you need to write out many values.
If it encounters a non trivial type you'll apply this recursive pattern again.
The end result is a recursive algorithm that traverses your object model and writes out values as it encounters types that I know how to serialize.
However, I do recommend looking into WCF, not for building services, but for serialization. It shipped as part of the .NET 3.0 framework with a new assembly System.Runtime.Serilization and in general is very capable when dealing with serialization and data annotations.

Categories

Resources