Entity Framework 6 Custom Pluralization in VB.Net - vb.net

I would like to take advantage of the new ability to customize pluralization with EF6. I've searched the entire intertwangles but can't find a decent example.
I generate my model from the database (SQL Server) and I use custom T4 templates to generate the context and model classes.
From what I can tell, I should be able to create a class which inherits from DbConfiguration and simply place it in the model project. I have done this.
Public Class CustomConfiguration
Inherits DbConfiguration
Public Sub New()
MyBase.New()
SetPluralizationService(New CustomPluralizationService)
End Sub
End Class
This class references CustomPluralizationService which I understand must implement IPluralizationService. Fine and dandy:
Imports System.Data.Entity.Infrastructure.Pluralization
Public Class CustomPluralizationService
Implements IPluralizationService
Public Function Pluralize(word As String) As String Implements System.Data.Entity.Infrastructure.Pluralization.IPluralizationService.Pluralize
End Function
Public Function Singularize(word As String) As String Implements System.Data.Entity.Infrastructure.Pluralization.IPluralizationService.Singularize
End Function
End Class
Of course I should complete the implementation of the Pluralize and Singularize functions, but am at a loss how exactly to do it, as I cannot find a completed example anywhere, in any language. Can someone help, please?
The documentation on MSDN has cryptic garbage like this:
Function Pluralize ( _
word As [%$TOPIC/dn176961_en-us_VS_113_3_0_0_0_0%] _
) As [%$TOPIC/dn176961_en-us_VS_113_3_0_0_0_1%]
Dim instance As [%$TOPIC/dn176961_en-us_VS_113_3_0_1_0_0%]
Dim word As [%$TOPIC/dn176961_en-us_VS_113_3_0_1_0_1%]
Dim returnValue As [%$TOPIC/dn176961_en-us_VS_113_3_0_1_0_2%]
returnValue = instance.Pluralize(word)
[%$TOPIC/dn176961_en-us_VS_113_3_0_2_0_0%] Pluralize(
[%$TOPIC/dn176961_en-us_VS_113_3_0_2_0_1%] word
)
[%$TOPIC/dn176961_en-us_VS_113_3_0_3_0_0%]^ Pluralize(
[%$TOPIC/dn176961_en-us_VS_113_3_0_3_0_1%]^ word
)

Related

Shared function that infers the class type and can be returned in a list

I would like to create a shared function that returns a list of instances of the classes type. Currently this is what my code looks like
class MyClass
Implements BusinessObject
Shared Function LoadAll(Of T As {BusinessObject, New})() As IEnumerable(Of T)
Dim helper = New SQLHelper()
Return helper.LoadDataTableFromDatabase("LoadTable", LoadAllProcedureName).Rows.Cast(Of DataRow).Select(Function(s) New T().FillDataRow(Of T)(s))
End Function
End Class
class MyDerivedClass Implements MyClass
End MyClass
When I go to use it, I have to use it like this:
MyDerivedClass.LoadAll(Of MyDerivedClass)()
I would like to be able to infer the type, instead of having to use the (Of MyDerivedClass) so that my code looks like MyDerivedClass.LoadAll().
Any help or keywords that I am missing to achieve this would be greatly appreciated.
Here is an extension method which (theoretically) would work on any class you define:
Public Module Module1
<Extension()> _
Public Function LoadAll(Of T As {BusinessObject, New})(ByVal x As T) As IEnumerable(Of T)
Dim LoadAllProcedureName As String = "LoadAllProcedure"
Dim helper = New SQLHelper()
Return helper.LoadDataTableFromDatabase("LoadTable", LoadAllProcedureName).Rows.Cast(Of DataRow).Select(Function(s) New T().FillDataRow(Of T)(s))
End Function
Public Sub Main()
Dim dC As New DerivedClass()
Dim allDc As IEnumerable(Of DerivedClass) = dC.LoadAll()
'::: Somewhat shorter syntax
Dim allDC As IEnumerable(Of DerivedClass) = (New DerivedClass()).LoadAll()
End Sub
End Module
But, as others have pointed out, this doesn't really clean anything up for you. More to the point, you are going to have to type (Of DerivedClass) in whatever variable you intend on populating with your enumerated DerivedClass, no?
And from what I can tell, you cannot have Shared extension methods -- should you be thinking that is the way to go.

Method doesnt want to move to Generic Class

I am wrapping a COM API.
In general, I have had good luck designing some generic classes and shoving the tested parts down into those classes.
Here is one that is giving me a problem.
There are classes that represent result sets. They do not inherit, they do implement a common interface, but it is a very simple interface. It does not expose the ResultSet functionality, specifically .COUNT or .GetAt(i)
My workaround is to make this a MustInherit and use CodeSmith to do the work for me. Not the end of the world. 13 more lines of generated code per entity.
I have played around with a class that might bridge this, and an interface that might bridge this, but I keep coming back to the fact that there is no common 'thing' in the API that represents a result set.
I may be missing something, I certainly am not seeing the solution.
The code for one instance of the work around is listed below
I would like to move this function to the Generic. It currently sits in each instance of class that uses the generic.
ICustomerRetList inherits from IBase. IBase has neither .Count or .GetAt() as mentioned above.
To be clear- My question is this : Can you suggest a vb construct that will allow me to move this function from my concrete class, down to my generic class
Public Overrides Function RetListToList(RetList As ICustomerRetList) As List(Of Customer)
Dim oItem As ICustomerRet
Dim oItem As Customer
Dim l As New List(Of Customer)
For idx = 0 To RetList.**Count** - 1 '.Count is not a member of IBase
oqbItem = RetList.**GetAt**(idx) '.GetAt() is not a member of IBase
oItem = New Customer()
'add the Item to the list
Call l.Add(oItem)
Next
Return l
End Function
If all implementations of IBase have these methods, and they all have the same names, you could combine extension methods and reflection to effectively lower the functions.
Public Class CustomerRetListExtensions
<Extension()>
Public Function GetAt(ByVal list As IBase, ByVal idx As Integer) As IBase
Return DirectCast(list.GetType().GetMethod("GetAt").Invoke(list, New Object() { idx }), IBase)
End Function
' If Count is a property, otherwise use the same approach as for GetAt
<Extension()>
Public Function Count(ByVal list As IBase) As Integer
Return DirectCast(list.GetType().GetProperty("Count").GetValue(list), Integer)
End Function
End Class

So a VB interface can't have shared functions. Is there an alternative to creating dummy objects?

To avoid getting into the weeds on my particular program, let me just create a simplified case.
I have a generic class that should work on a variety of objects. Each of those objects must implement a certain interface.
What I WANT to say is something like:
Public Interface GenThing
Shared Function thing_name() As String ' This doesn't work! Can't be shared!
Sub FillOne(row As DataRow)
End Interface
public class Thing1
implements GenThing
public shared function thing_name() as string implements GenThing.thing_name
return "thing number one"
end function
public sub FillOne(row as DataRow) implements GenThing.MakeOne
... bunch of work ...
end sub
end class
public class ThingUtil(of T as {GenThing,New})
public function GetList(id as integer) as List(of T)
dim name=T.thing_name() ' This doesn't work!
dim ds as DataSet=GetData(name,id) ' bunch of work here that's the whole point of the class but not relevant to the question
dim my_list = new List(of T)
for each row as DataRow in ds.tables(0).rows
dim my_t = new T()
my_t.FillOne(row)
my_list.add(my_t)
next
return my_list
end function
end class
Do you get my problem? I need every class that implements the interface to have a function that returns a "name" that is used to get the data that is needed to create an instance of the object. But I need to know this name BEFORE I create the instance, because I need it to be able to create the instance. But VB doesn't allow an interface to have a shared function, so what I want to write doesn't work.
So what I've done is this:
I make thing_name not shared.
Then instead of simply "dim name=T.thing_name()", I write
dim dummy = new T()
dim name = dummy.thing_name()
Okay, it works, but it seems really ugly. I create an instance of the object, with all the overhead that that involves, just to get a piece of constant text.
Is there a better way? Or am I making a big deal out of nothing?
Update
I see that two people voted to close this question on the grounds that it is the same as "Why can't we have shared functions in an interface?"
I am not asking why I can't have a shared. I am saying, GIVEN that I can't, how do I solve this particular problem?
There's no really simple way of fixing this, no.
Depending on what thing_name does, however, you might approach things in a different way. If each implementation just returns a constant value, then it's effectively metadata about the class - and could be described in an attribute instead, which can be fetched at execution time. (See Type.GetCustomAttributes.) Unfortunately you can't then enforce all types implementing the interface to be decorated with the attribute - but you could write a unit test to check this pretty easily.
If thing_name needs to really do work at execution time, that's tougher. You could potentially look for a well-known shared method name instead and execute that via reflection (and again have unit tests to check that it's implemented properly).
I realize this is from a few years ago, but running into a similar problem, I wanted to offer a different solution. Pass a delegate as parameter to the ThingUtil constructor. You avoid having to put a shared method in an interface, and the constructor will force you to include the parameter at compile time.
You can add more delegates if needed, or to make it even simpler in this case, just pass name as a string instead of get_name as a delegate.
Define the delegate in the interface:
Public Interface GenThing
Delegate Function ThingNameDelegate() As String
Sub FillOne(row As DataRow)
End Interface
Public Class Thing1
Implements GenThing
Public Shared Function thing_name() As String 'name this whatever you want
Return "thing number one"
End Function
Public Sub FillOne(row As DataRow) Implements GenThing.FillOne
'do stuff
End Sub
End Class
In ThingUtil, add a member to store the delegate, a constructor parameter to to accept, and call it with .Invoke():
Public Class ThingUtil(Of T As {GenThing, New})
Private m_thing_name As GenThing.ThingNameDelegate
Public Sub New(thing_name As GenThing.ThingNameDelegate)
m_thing_name = thing_name
End Sub
Public Function GetList(id As Integer) As List(Of T)
Dim name = m_thing_name.Invoke()
Dim ds As DataSet = GetData(name, id) ' bunch of work here that's the whole point of the class but not relevant to the question
Dim my_list = New List(Of T)
For Each row As DataRow In ds.Tables(0).Rows
Dim my_t = New T()
my_t.FillOne(row)
my_list.Add(my_t)
Next
Return my_list
End Function
End Class
Finally, use it like this:
Dim tu as new ThingUtil(Of Thing1)(AddressOf Thing1.get_name)
tu.GetList(1)

Base Classes on Proxy Objects

I have a webservice that is wrapped up by a data access object and is accessed by many different UI controls.
The proxy objects look something like this:
Public Class WebProxyObject1
' Common properties, there are about 10 of these
Public Name As String
Public Address As String
' Specialized properties there are about 20 of these
Public count As Integer
End Class
The DAL layers look something like this:
Public Class DataAccessObject
Implements IDataAccessObject
' These are called in MANY, MANY, MANY locations
Public Function GetObject(ByVal name As String) As WebProxyObject1 Implements IDataAccessObject.GetObject
' Makes call to a webservice
Return New WebProxyObject1
End Function
Public Function ListObjects() As System.Collections.Generic.List(Of WebProxyObject1) Implements IDataAccessObject.ListObjects
' Makes call to a webservice
Dim list As New List(Of WebProxyObject1)
Return list
End Function
End Class
Now, I need to add a 2nd webservice to the mix. The goal is to reuse the UI controls that are currently coded to use the Proxy Objects that come from the first webservice. There are about 10 common properties and about 20 that are different. To add the 2nd webservice, I'd create a 2nd DAL object that implements the same interface. The problem is that it currently returns the proxies from the first webservice.
My thought on how to solve this is to extract an interface from each of the proxy objects and mash them together. Then implement the new interface on both proxy objects. That will create a huge class/interface where some properties aren't used. Then have the DAL return the interface.
The problem that I'm facing isn't a real bug or an issue, but extracting the 2 interfaces and smashing them together just feels kind of wrong. I think it would technically work, but it kind of smells. Is there a better idea?
The resulting interface would look like this:
Public Interface IProxyObject
' Common
Property Name() As String
Property Address() As String
' Specialized
Property Count() As Integer
Property Foo() As Integer
End Interface
Create a base class for your WebProxyObjects to inherit from.
Public MustInherit Class WebProxyObjectBase
' Common properties
Public Property Name As String
Public Property Address As String
End Class
Next create your two WebProxyObjects:
Public Class WebProxyObject1
Inherits From WebProxyObjectBase
' Specialized properties
Public Property count As Integer
End Class
Public Class WebProxyObject2
Inherits From WebProxyObjectBase
' Specialized properties
Public Property foo As Integer
End Class
Next have your DAL return the Base Class:
Public Class DataAccessObject
Implements IDataAccessObject
' These are called in MANY, MANY, MANY locations
Public Function GetObject(ByVal name As String) As WebProxyObjectBase Implements IDataAccessObject.GetObject
' Makes call to a webservice
Return New WebProxyObjectBase
End Function
Public Function ListObjects() As System.Collections.Generic.List(Of WebProxyObjectBase) Implements IDataAccessObject.ListObjects
' Makes call to a webservice
Dim list As New List(Of WebProxyObjectBase)
Return list
End Function
End Class
Then when calling your DataAccessObject you'll be able to ctype the return to the proper class:
Dim DAO as New DataAccessObject
Dim Pxy1 as WebProxyObject1 = TryCast(DAO.GetObject("BOB"), WebProxyObject1)
If Pxy1 IsNot Nothing Then
'Do stuff with proxy
End If

VB.NET: How to reference VB.NET module?

I got a Utility module since VB.NET doesn't have static class like C# and Module is the static class in VB.NET. The reason that I use module is because I'm using the Extension method and it can only be use in Module.
I can't reference to this module but if I put my code in a class. I can reference to it without any problem. What could be the reason? I missed C#.
Edit: The module is inside a class library call Utility.
You need to mark the module as Public Module.
I can't reference to this module but if i put my code in a class. I can reference to it without any problem. Does anyone know why?
Because Modules in VB aren't classes and can't be used to instantiate objects. Rather, they're something similar to namespaces, with the difference that namespaces can't contain functions directly. So the reason for modules is to provide a way to group functions logically that don't belong to a class.
This makes a lot of sense when you consider that not everything logically belongs to a class. Consider System.Math. There is absolutely no reason to make that a class, other than a weird OOP purism.
By the way, you can't reference static classes in C# either, at least not if I understand correctly what you mean by “reference”. Perhaps you can clarify this.
.NET compilers can take any type of language syntax and turn it into a .NET equivalent. Sometimes there is a one for one correspondence other times there isn't.
By using the .NET Reflector you can see what the compiler is really doing.
In VB.NET the module exists because of the heritage inherited from Visual BASIC and partly from Microsoft BASIC.
The VB.NET compiler will take this
Public Module CoreModule
Dim R As New System.Random(CInt(Microsoft.VisualBasic.Timer))
Public Function D(ByVal Roll As Integer) As Integer
Return R.Next(0, Roll) + 1
End Function
Public Function _1D6() As Integer
Return D(6)
End Function
Public Function _2D6() As Integer
Return D(6) + D(6)
End Function
Public Function _3D6() As Integer
Return D(6) + D(6) + D(6)
End Function
Public Function _4D6() As Integer
Return D(6) + D(6) + D(6) + D(6)
End Function
Public Function CRLF() As String
Return Microsoft.VisualBasic.ControlChars.CrLf
End Function
End Module
And turn it into this (code left out for brevity)
Public NotInheritable Class CoreModule
' Methods
Shared Sub New()
Public Shared Function _1D6() As Integer
Public Shared Function _2D6() As Integer
Public Shared Function _3D6() As Integer
Public Shared Function _4D6() As Integer
Public Shared Function CRLF() As String
Public Shared Function D(ByVal Roll As Integer) As Integer
' Fields
Private Shared R As Random
End Class
In C# the equivalent is this
public sealed class CoreModule
{
// Fields
private static Random R;
// Methods
static CoreModule();
public static int _1D6();
public static int _2D6();
public static int _3D6();
public static int _4D6();
public static string CRLF();
public static int D(int Roll);
}
All that matter is that the emitted CIL does the job correctly.
This capability is the main reason why so many older Visual BASIC 6 programmers are highly annoyed at MS's changes to the language. For example the keyword Integer emitting a Int32 instead of a Int16.
Modules are exposed to other assemblies referencing the original assembly as long as the module is declared public.
Maybe the methods/subs aren't public? I had that problem once, and it would allow access local code in your class, but not if it was outside your class and marked "Private".
Imports System.Web
Imports System.Web.UI
Module ResponseHelper
<System.Runtime.CompilerServices.Extension()> _
Public Sub Redirect(ByVal response As Net.HttpWebResponse, _
ByVal url As String, ByVal target As String, _
ByVal windowFeatures As String)
If String.IsNullOrEmpty(target) Or _
target.Equals("_self", StringComparison.OrdinalIgnoreCase) And _
String.IsNullOrEmpty(windowFeatures) Then
response.Redirect(url, target, windowFeatures)
Else
Dim page As Page = CType(HttpContext.Current.Handler, Page)
If page Is Nothing Then
Throw New InvalidOperationException("Cannot redirect to new window outside Page context.")
End If
url = page.ResolveClientUrl(url)
Dim script As String
If String.IsNullOrEmpty(windowFeatures) Then
script = "window.open(""{0}"", ""{1}"", ""{2}"";"
Else
script = "window.open(""{0}"", ""{1}"");"
End If
script = String.Format(script, url, target, windowFeatures)
ScriptManager.RegisterStartupScript(page, GetType(Page), "Redirect", script, True)
End If
End Sub
End Module
I don't understand what you are asking.
VB.NET does have static classes, just like in C#, because in VB.NET a Module IS a static class. They are one and the same. Anything you can do with a static class you can do with a Module. Perhaps you haven't marked your Public/Private/Protected access correctly?