How to manage multiple tables with the same structure (redux) - vb.net

I found this question, which is similar to a problem that I would like to solve:
How to manage multiple tables with the same structure
However, due to the craptastical nature of VB, the solution doesn't really work. It specifically doesn't work because VB.NET requires the implementation of each method/property in the interface to be explicitly declared.
As for the problem that I'm really trying to solve, here it is:
I have many lookup/domain tables in the database that all have the same structure
The items in these tables are typically used for drop downs in the interface
I would like to avoid a bunch of boilerplate repository methods to retrieve the contents of these tables (one method per table really sucks when you have 40 tables)
I am not using the One True Lookup Table anti-pattern and this is not an option
Does anyone have another solution for this that work work in VB?

Generic Repository should work in this case. There are many available online or you can write a simpler one for just the lookup tables.

Here is the code that we ended up using:
Public Function GetDomainTableList(tableName As String) As IEnumerable(Of Object)
Dim table = CType(GetType(FECEntities).GetProperty(tableName).GetValue(DB, Nothing), IEnumerable(Of Object))
Dim dt = From r In table
Select r
Return dt.ToList()
End Function
I had originally thought that this wouldn't work for us since I was trying to project each object returned into a DomainTableItem class that I had written. But then I realized that the SelectList constructor didn't really care about the type of object that it takes in. You just pass in a String containing the property name and it uses reflection to pull out the value.
So everything works out peachy this way and I avoided writing one method per domain/lookup table.

Related

How to clear the contents of an IEnumerable

Dim sortQuery = From results In resultList
Order By results.getUsername()
Where results.getUsername() = passUsername
Select results.getAll()
For Each Str As String In sortQuery
lstBox.Items.Add(Str)
Next
I have created a generic IEnumerable of objects. The object class is results, resultList is a list of many instances of that object. In order to carry out multiple queries, I intend to repeat this code but with different conditions.
When this code is repeated, it outputs results for that search in addition to all results from previous searches made. I believe that clearing the IEnumerable between queries will prevent this. Is there a way to do this? Alternatively, how could I make it so that each query outputs only the results for that query and not those for the previous ones as well?
You can't clear an IEnumerable(Of T). That interface just means that you can enumerate a list of items. It says nothing about how those items are stored. In the case of a LINQ query, it's not the items that are stored but information on how to get them from a source list. The list of items that results from executing the query is not stored separately anywhere to clear but is generated by applying the query logic each time.
If you want to execute similar but different queries then you need to create multiple queries. You can create a single base query that contains the common logic and then you can just apply the specific parts to each specific query. For instance, if you wanted to get all the Person objects from a list but you wanted the males and females separately then you could do this:
Dim baseQuery = From person In people
Where person.FamilyName = "Smith"
Dim maleQuery = From person In baseQuery
Where person.Sex = Sex.Male
Dim femaleQuery = From person In baseQuery
Where person.Sex = Sex.Female
All three of those queries are stored as logic, not as objects. When you enumerate maleQuery or femaleQuery, you are executing that logic and getting the results one by one. In each case, the logic stored in baseQuery is executed as well as the logic in the more specific query so you get both filters applied at the same time.
EDIT: I should clarify and say that you cannot clear an IEnumerable(Of T) via that interface. For instance, a List(Of T) implements the IEnumerable(Of T) interface and you can clear that, but it's that class that provides that functionality. If all you know about an object is that it implements IEnumerable(Of T) then you can't clear it because you have no idea if it has functionality besides that defined by that interface. A LINQ query definitely doesn't have such functionality because there's no actual concrete list to clear.

How to write clear and maintainable code when dealing with tables?

In my projects I often take advantage of tables and underlying ListObjects and ListColumns. I like them as they're easier to reference and update than bare Range objects. Yet I still haven't found a sane and maintainable way to handle multiple ListObjects consisting of many ListColumns and being referenced across all Worksheets in a project.
Let's say I have Worksheet (with (Name) property set to "WorksheetA") that contains table (called TableA) with few columns (called Column1, Column2, ..., Column10).
Now I want to reference one of the columns from the code of another Worksheet. I could do it as follows:
WorksheetA.ListObjects("TableA").ListColumns("Column7")
Now, it's a bad practice to use string directly, as it's difficult to maintain and prone to errors.
So what now?
I could create dedicated module to store my string as constants. For example, module called "Constants":
Public Const TABLE_A As String = "TableA"
Public Const COLUMN7 As String = "Column7"
Then my reference could be converted to:
WorksheetA.ListObjects(Constants.TABLE_A).ListColumns(Constants.COLUMN7)
However, this solution has some disadvantages:
Constants module would grow ridiculously fast with each table and column added.
Reference itself grows and becomes less readable.
All constants related to tables from across all workbooks are thrown into one giant pit.
I could store constants inside WorksheetA, and make them available through Public Functions like:
Private Const TABLE_A As String = "TableA"
Private Const COLUMN7 As String = "Column7"
Public Function GetTableAName() As String
GetTableAName = TABLE_A
End Function
Public Function GetTableA() As ListObject
Set GetTableA = WorksheetA.ListObjects(TABLE_A)
End Function
Public Function GetTableAColumn7() As ListColumn
Set GetTableAColumn7 = GetTableA().ListColumns(COLUMN7)
End Function
This solution actually solves all three problems mentioned above, yet it's still a bit "dirty" and time-consuming, as adding a new table introduces a requirement to create a function for each column.
Do you have better idea how to deal with this problem?
EDIT1 (for clarity): Let's assume that user must not change any names (neither table names nor column names). If user does so, it is he/she to blame.
EDIT2 (for clarity): I've used Column7 as column name only as an example. Let's assume that columns have more meaningful names.
Here's my two cents. I'm not an educated programmer, but I do get paid to do it, so I guess it makes me professional.
The first line of defense is that I create a class to model a table. I fill the class from the table and no other code even knows where the data lives. When I initialize, I'll run code like
clsEmployees.FillFromListObject wshEmployees.ListObjects(1)
Then in the class, the code looks like
vaData = lo.DataBodyRange.Value
...
clsEmployee.EeName = vaData(i,1)
clsEmployee.Ssn = vaData(i,2)
etc
Only one ListObject per worksheet. That's my rule and I never break it. Anyone with access to the worksheet could rearrange the columns and break my code. If I want to use Excel as a database, and sometimes I do, then that is the risk I take. If it's so critical that I can't take that risk, then I store my data in SQL Server, SQLite, or JET.
Instead of putting the range in an array, I could actually call out the ListColumns names. That way if someone rearranged the columns, my code will still work. But it introduces that they could rename the columns, so I'm just trading one risk for another. It would make the code more readable, so it may be the trade you want to make. I like the speed of filling from an array, so that's the trade I make.
If my project is sufficiently small or is supposed to work directly with ListObjects, then I follow the same rules as I do for any Strings.
I use Strings in code exactly once.
If I uses it more than once, I make a procedure-level constant
If I use it in more than one procedure, I try to pass it as an argument
If I can't pass it as an argument, I make a module-level constant
If the two procedures are in different modules, I first ask myself why two procedures are in different modules that use the same constant. Shouldn't related procedures be in the same module?
If the two procedures really belong in the different modules, then I try to pass it as an argument
If none of that works, then it truly is a global constant and I set up in my MGlobals module.
If MGlobals takes up more than about half a screen, I'm doing something wrong and I need to step back and think through what I'm trying to accomplish. And then I make a custom class.

load record by predicate/lambda via vb.net linq

im pretty confused about lambdas and actually im not even sure i need them here
what im trying to do here is write a function that will return an object from a certain table with a certain criteria
so lets say i can write
function GetRecord(TableName as string,Criteria as string) as object
'do the linq-stuff
end function
now i dont care if the paremeters are strings or lambdas or whatever, but the end result must be that at runtime i dont know which table and which criteria will be used
as sometimes i need to get a customer record by email and sometimes a product by id etc.
if possible i would prefer returning a list of matching objects and then i would just use .firstordefault when i want 1 (such as by id...)
thank you , as always, for taking the time to read this and answer!
all the best
Have you considered using Dynamic LINQ?
Example:
Parsing an expression tree can be a challenging but rewarding method of solving this issue. I think it's overkill and I'd go with Dynamic Linq as decyclone mentioned.
A benefit of parsing the expression tree, however, is that you can have compile time checking of the submitted criteria.
Here are some articles that helped me.
How to: Implement an Expression Tree Visitor: http://msdn.microsoft.com/en-us/library/bb882521(VS.90).aspx
Building a custom IQueryable Provider: http://blogs.msdn.com/b/mattwar/archive/2008/11/18/linq-links.aspx
Walkthrough: Creating an IQueryable LINQ Provider: http://msdn.microsoft.com/en-us/library/bb546158(v=VS.90).aspx
Expression Tree Basics:
http://blogs.msdn.com/b/charlie/archive/2008/01/31/expression-tree-basics.aspx

vb.net Module for data access - how bad is this?

I've inherited some code that has a Public Module for data access:
Code looks like:
Public Module Foo
Dim ds As New DataSet
Public Function GetDataSet(ByVal sqlQuery As String) As DataSet
...
Fill(ds)...
...
return ds
End Function
End Module
And all the pages call GetDataSet(sql). Am I correct is assuming that this is a bad idea? Worst case is that concurrent callers could get each others data?
Your concerns about concurrent callers is well founded. The solution is to just move the "Dim ds.." from the module into the GetDataSet routine. Then its local, on the stack, and theres no chance of stepping on each other.
A larger problem is that composing SQL queries as string in client code is not good application design, it can be OK for SQL utilities, but nothing else. This approach will keep you from using Linq to SQL, Linq to Entities, Stored Procedures, most of the more desirable DB-access security models and probably exposes you to SQL Injection attacks.
Very bad. With that architecture there is absolutely no way to use a parameterized query or stored procedure to protect yourself from SQL Injection...and that's just a start.
You're also going to be missing out on any kind of strongly typed data sets (which make life a whole lot easier).
i use something similar to this and have never had any problems. makes data access sooo easy. i don't mind writing SQL and in fact it kind of helps me understand exactly what data i'm getting. so long as data access is clearly separated (ie, you pull data consistently from the same location), and you sanitize all data in the SQL string, i don't see anything wrong w/this. i do agree that public variable is bad, though.
sigh... or maybe i'm a bad programmer :\ let the downvoting begin...

Best Way to Handle SQL Parameters?

I essentially have a database layer that is totally isolated from any business logic. This means that whenever I get ready to commit some business data to a database, I have to pass all of the business properties into the data method's parameter. For example:
Public Function Commit(foo as object) as Boolean
This works fine, but when I get into commits and updates that take dozens of parameters, it can be a lot of typing. Not to mention that two of my methods--update and create--take the same parameters since they essentially do the same thing. What I'm wondering is, what would be an optimal solution for passing these parameters so that I don't have to change the parameters in both methods every time something changes as well as reduce my typing :) I've thought of a few possible solutions. One would be to move all the sql parameters to the class level of the data class and then store them in some sort of array that I set in the business layer. Any help would be useful!
So essentially you want to pass in a List of Parameters?
Why not redo your Commit function and have it accept a List of Parameter objects?
If your on SQL 2008 you can use merge to replace insert / update juggling. Sometimes called upsert.
You could create a struct to hold the parameter values.
Thanks for the responses, but I think I've figured out a better way for what I'm doing. It's similar to using the upsert, but what I do is have one method called Commit that looks for the given primary key. If the record is found in the database, then I execute an update command. If not, I do an insert command. Since the parameters are the same, you don't have to worry about changing them any.
For your problem I guess Iterator design pattern is the best solution. Pass in an Interface implementation say ICommitableValues you can pass in a key pair enumeration value like this. Keys are the column names and values are the column commitable values. A property is even dedicated as to return the table name in which to insert these value and or store procedures etc.
To save typing you can use declarative programming syntax (Attributes) to declare the commitable properties and a main class in middleware can use reflection to extract the values of these commitable properties and prepare a ICommitableEnumeration implementation from it.