I have inherited a badly designed database and have to convert the old code to MVC & EF.
I would like to be able to assign a database table name to a variable dynamically from within a SWITCH...CASE.
The table design is exactly the same, but there is a different table for different areas of the business!
How would I go about doing this? I am probably missing something extremely basic!
The code I currently have looks something like the following.
Declare the database
private CDBEntries db = new CDBEntries();
ActionResult Below
var cMembs = db.XXXcmembs;
switch (returnValue.ToUpper())
{
case "CRI":
cMembs = db.YYYsmembs;
break;
default:
break;
}
cSearchQuery = (from CCM in cMembs
join CC in cDB on CCM.name equals CC.cname into CGroup
from CC in CGroup.DefaultIfEmpty()
select new CSearch()
{
id = CCM.id,
Name = CCM.name,
Status = CCM.status,
cid = CC.id
});
There are more joins in the live code, but for simplicity I have reduced the code to its basics.
Don't think you will be able to use var like that. Var is strongly typed and declared at compile type.
var (C# reference)
An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type
You might be able to use dynamic, which is inferred at run-time.
Walkthrough: Creating and Using Dynamic Objects
Dynamic objects expose members such as properties and methods at run time, instead of at compile time.
Let me know if you struggle, I will see if its possible from my side later today.
After further research I have realised that what I want to do goes against the reason for using EF (i.e. compile time validation).
As all of the tables have the same layout I am going to 'merge' them into 1 table with an extra column to specify the area.
Related
Lets say I have an IEnumerable
IEnumerable<Students> = from a in context.Students select a
Is there any way to execute
from a in context.Students select a
from a string?
You can do it like this:
From MSDN
Northwnd db = new Northwnd(#"c:\northwnd.mdf");
IEnumerable<Customer> results = db.ExecuteQuery<Customer>
(#"SELECT c1.custid as CustomerID, c2.custName as ContactName
FROM customer1 as c1, customer2 as c2
WHERE c1.custid = c2.custid"
);
However it also loses some of the key benefits of using an ORM in the first place. Automatic data binding and automatic parameter binding (thus preventing SQLi attacks)
'Is there any way...?'
Sure there is. This is basically a piece of C# code that you want to run. So all you need is a way to compile this piece of code into a valid assembly, load the assembly and run this piece of code. The .NET Compiler Platform ("Roslyn") or maybe even CodeDom can help you with that. But bear in mind that this can be quite complicated.
This is a contrived example however I have simplified it for ease of explanation.
Please see my update at the bottom before investing too much of your
time!
Background
I have some (a lot of) code that ordinarily queries my DB as follows:
SELECT name FROM sites where IsLive=1;
My challenge is to, under certain conditions, return the full list of sites, essentially
SELECT name from sites;
I do not wish to modify the actual C# code issuing the SQL (although I can do if I have to in order to achieve my goal which is purely for demonstration purposes).
Therefore in order to leave as much untouched as possible my thoughts are to insert a database-proxy-view called site that returns the data dependent on a control variable
Method
Rename existing site table to site_table
Create a new view named site that the C# code now unknowingly targets and which returns the (possibly filtered) details from site_table according to the control variable value (Note a limitation on variables in views meant I had to create a function in order to demonstrate this - see http://dev.mysql.com/doc/refman/5.7/en/create-view.html wrt error 1351)
Changes made
ALTER TABLE site RENAME TO site_table;
CREATE FUNCTION controlVariableFn() RETURNS VARCHAR(16) RETURN #controlVariable;
CREATE OR REPLACE VIEW site AS SELECT * from site_table WHERE (IsLive = 1 OR controlVariableFn() = 'SHOWALL');
The above statements are ugly but achieve the result I want, however my problem is to dynamically pass through controlVariable without changing my main SQL queries being sent.
My Question
Is there a way to (ideally as I am creating my connection object) define the controlVariable outside the actual SQL to be executed but which the View can still access similar to the above as though it had been supplied as a regular user variable parameter to the query?
so the code would look something like
var connectionString = "Server=localhost;User ID=un;Password=pw;Database=dbname;....";
DbConnection db = new MySql.Data.MySqlClient.MySqlConnection
(connectionString, "controlVariable=SHOWALL");
var results = db.Query<Site>("SELECT * FROM site;");
(I understand that this would not be a smart permanent solution)
Update
My preferred solution as outlined above will not work for me as once I get into my data access layer as the results set will
essentially be filtered again back to the original set. There are some circumstances where it
could work; it would depend on the SQL issued (e.g. when collapsing a
results set down instead of trying to expand a results set as I was
trying to do here).
In that regard I am no longer looking for an answer here but will leave it for posterity as a preferred option and as per the guidelines - thanks anyway.
If you do not want to edit the c# code then the variable will have to be stored in the database although i am not sure how you will not edit the code.
If you are willing to edit the code then you can access a secondary configuration table which will have the settings that you would like the user to pass to the view. take this and allow the user to select which they want and then pass it to the view through the application.
I'm attempting to create a generic WPF form or page, that when called, will load in data from a LINQ table. Here is the concept:
I have three tables in a LINQ DataContext that are identical (apart from the data within)
TypeID and Type are the columns
I would like to generically pass that data in those tables into my second form depending on which table the user selects (essentially so they can narrow down the list of objects of said Type.
I've seen some responses, (in particular the accepted answer to this one LINQ query with a generic table) that are very close to what I am looking for, but not quite. One issue I have with the above answer is that T must be a reference type.
I've done more searching and found some more answers like:
someClass<T> : <T> where T
But unfortunately these are further from my own context and I am unable to bridge the two concepts of what is happening. Below I have posted what I hope to do.
someDataContext db = new someDataContext();
private void pageLoader<T>(){
newPage n = new newPage(T) //This is where I was hoping I could pass the table(s) to the constructor.
}
And here is the constructor:
newPage(T){
listBox l = new listBox();
l.datasource = T;
}
Any assistance in any direction would be helpful (besides MSDN, please. I've been there and I'm still lost.)
Let start from the top. LINQ is merely an abbreviation for Language Integrated Query. It is interchangeable with Lambda. Different syntax but both accomplish the same task. Querying a collection or datasource. See http://msdn.microsoft.com/en-ca/library/bb397926.aspx
You are referring to the EntityFramework Code First approach of creating a database. LINQ is merely a way to access and manipulate the information within.
With that out of the way, what you are pointing out is a Generic Method and a Generic Class. T is simply a standard naming convention for a generic type. You could use any representation you like. If you are going to be passing in entities, you might use TEntity for example.
See http://www.dotnetperls.com/generic-method
http://www.dotnetperls.com/generic
When you see someClass where T, this is a constraint for type parameters.
And finally, what you have been waiting for...
https://codereview.stackexchange.com/questions/19037/entity-framework-generic-repository-pattern
The following should put you on the right path.
http://blog.gauffin.org/2013/01/repository-pattern-done-right/ <- This would be more of a better starting tutorial
I'm trying to create a pivot of a translation table. Basically the table is like that :
SystemText(Category, Name, LanguageCode, Text)
I have created a model object which has these fields as properties and I'm using NHibernate to get the data from the database.
Now what I want to display is a grid to edit the translations that will display on the same line the category, the name of the text and all the available languages (languages that are not fixed in advance). For example :
Category | Name | English | French | German
I've managed to create a Linq query to create the pivot that I will need to do that. It looks like that
Dim test = From systemText In _systemTexts _
Group systemText By Key = New With {Key systemText.TextCategory, Key systemText.TextName} Into g = Group _
Select New With {Key .TextCategory = Key.TextCategory, _
Key .TextName = Key.TextName, _
.Languages = g.ToDictionary(Function(st) st.LanguageCode, Function(st) st.Description)}
Now the only trouble I have is to bind the objects to my gridlist. I would create the columns of the grid dynamically when the form is loading, depending on the languages available. I thought that using something like Languages("EN") in the DataMember property would work, but it doesn't seem so.
I'm a bit blocked now, I thought about using something else to replace the Dictionary for the languages but I don't really see what I can use.
So, after some trial and error I ended finding some ways to do that.
The first, and one of the most complex ways of doing it I have found was was given by Vladimir Burodov on this blog post. The idea basically is to dynamically create an anonymous type that has a property for each key in the Dictionary. It's very clever and very useful, but a bit overkill for the little task I needed.
Another way around was using Custom Property Descriptors. The idea is to create a custom list type that will, when asked for the special property call a custom function that will send back the value. Examples of this method can be seen here. Again unfortunately I couldn't use this method because the grid component I am using cannot use the custom property descriptors.
I also thought about using Dynamic Linq to generate dynamic queries where I would have been able to change the property names of the query result (see this Scottgu's article) but I didn't want to use another library just for the simple thing I needed.
Finally what I endend doing was dynamically creating a DataTable, inserting the result of the Linq query in it, binding the DataTable to the grid and finally listening to the RowUpdated event and do the CRUD operations to the NHibernate collections. It works quite nicely and the code is easy to understand.
Allow me to start with: I am a n00b on ASP.NET MVC. I love it, but I am a n00b.
I am trying to pass "complex" data back from a LINQ query. I understand how to use the data context and then just cast that data when I send it back, but when I do a more complicated LINQ query which returns an anonymous type, things break down.
I saw someone ask a similar question (MVC LINQ to SQL Table Join Record Display), and the answer seemed to be to create a new data type to capture the data from the LINQ query. I don't get that I can create a var type in the controller, and access the member fields within the controller, but if I want to pass that var back to my View, I need to create an entire new class for that.
Here’s my Controller code:
var vrGoodResults1 = from records in db.Words
group records by records.word1 into g
select new
{
strWord = g.Key,
intWordCount = g.Count()
};
ViewData["GoodWords"] = vrGoodResults1;
return View();
And the View looks like this:
<% foreach (var kvp in (IEnumerable)ViewData["GoodWords"]) %>
<% { %>
<%= String.Format("{0} was used times", kvp) %> <br />
<% } %>
Which outputs:
{strWord = cool, intWordCount = 2 } was used times
{strWord = educated, intWordCount = 1 } was used times
{strWord = great, intWordCount = 1 } was used times
{strWord = smart, intWordCount = 6 } was used times
{strWord = strong, intWordCount = 2 } was used times
{strWord = super smart, intWordCount = 2 } was used times
So the data is getting to the View, but I cannot refer to the data by the field names I assigned in the LINQ query. When I try dumping kvp.GetType(), I get:
<>f__AnonymousType1`2[System.String,System.Int32]
All I want to do is something along the lines of:
<%= String.Format("{0} was used {1} times", kvp.strWord, kvp.intWordCount) %> <br />
But I am getting a compile error on the kvp.strWord.
error CS1061: 'object' does not contain a definition for 'strWord' and no extension method 'strWord' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
If I insert the following code into my Controller:
foreach (var kvp in vrGoodResults1)
{
string strNew = kvp.strWord;
}
I can reference the fields of my variable kvp without a compile error. So something is getting lost when passing from the Controller to the View. Am I forgetting to include something somewhere? Perhaps a “using” or in the “<# Page” directive, am I forgetting to inherit something?
When you are using LINQ for clear data contexts, you just set the IEnumerable<”datatype”> where “datatype” = your data context type, and you are all good. When you reduce your data set into something new in LINQ, I can't believe that the best answer is to create a new class so that I can use it in my View.
var is a compiler shortcut for declaring a type in the current scope. It doesn't add any dynamic functionality to the .NET runtime, so code outside the scope sees the object as "System.Object", since that is the most-specific type in the inheritance chain the view code is aware of.
You should create a real class if you want to pass tuple objects around; that's what you had to do before var, so it's not like you're losing anything by having to do it now :)
The best answer here simply is to create a new type. You can do get anonymous types back from object (see here) but it is ugly and brittle. Don't do it!
You could use reflection (kvp.GetType().GetProperty("strWord").GetValue(kvp, null)) - but that also isn't a great idea.
In this case - perhaps use the existing KeyValuePair<string,int> from the original select? Or your own Tuple<T1,T2>?
Don't be afraid of new types. They give lots of other benefits too especially when testing. Use the new property syntax and your class will only be as many lines long as you have properties. You can lose that awful Hungarian notation too. Int and str - yuk