I'm just learning to work with partial classes in VB.NET and VS2008. Specifically, I'm trying to extend a LINQ to SQL class that was automatically created by SqlMetal.
The automatically generated class looks like this:
Partial Public Class DataContext
Inherits System.Data.Linq.DataContext
...
<Table(Name:="dbo.Concessions")> _
Partial Public Class Concession
...
<Column(Storage:="_Country", DbType:="Char(2)")> _
Public Property Country() As String
...
End Property
...
End Class
In a separate file, here's what I'm trying to do:
Partial Public Class DataContext
Partial Public Class Concession
Public Function Foo() as String
Return DoSomeProcessing(Me.Country)
End Function
End Class
End Class
... but I get blue jaggies under 'Me.Country' and the message 'Country' is not a member of 'DataContext.Concession'. Both halves of the partial class are in the same namespace.
So how do I access the properties of the automatically-generated half of the partial class, from my half of the partial class?
Unless VB.NET generates different stuff in its LINQ to SQL files from C# the classes of the DB tables aren't within the DataContext class, just beside it.
So you have the class MyNamespace.DataContext.Concession when the other half of the partial class is realy MyNamespace.Concession
(This related to VB.NET - might be differences with C# projects)
I put my entities in their own namespace by configuring the Linq-to-SQL model property.
e.g. MyCo.MyProj.Business.Entities
I then add non-Linq business entities in there too, so they are all in the same namespace.
However, when trying to do the above partial class additions, I found that the partial class (i.e. the one you generate, not the auto-generated LINQ class) MUST be in the same project as the Linq-to-SQL model. Otherwise in the Class View and Object Viewer you see two separate classes - seemingly in the same namespace, but not really. Not sure if this is a bug or I am doing something wrong.
But, anyway, putting the partial class file in the same project as your model works.
Related
I have a class that I would like to extend by defining a new class that contains the first class as a public property, as well as additional added properties. However, the class that I'm extending has multiple derived types, which should be treated the same in the extension class.
Below is an example of what I am trying to do:
Public Class ClassA
End Class
Public Class ClassB
Inherits ClassA
End Class
Public Class ClassC
Inherits ClassA
End Class
Public Class BaseExtended
Public Property Foo As ClassA
Public Property ExtendedMetaData1 As Double
Public Property ExtendedMetaData12 As Integer
End Class
Public Class DerivedExtendedB
Inherits BaseExtended
Public Property Foo As ClassB
End Class
Public Class DerivedExtendedC
Inherits BaseExtended
Public Property Foo As ClassC
End Class
The code that uses an instance of any of the 'extended' classes would then need use that instance appropriately depending on it's type. There would be many cases where the property 'Foo' needs to be accessed and modified outside of the class that it belongs to.
If I were to implement something like what I have shown above, that would require that I first cast it to the required type before accessing or modifying it. Ideally I would like to do that inside the 'DerivedExtended' class; The alternative, I think, would be to duplicate code to cast that property would [hundreds of times] in the client code.
Private Sub ClientUsesObject(bar As BaseExtended)
' Perform a task that is agnostic Foo type
' Would not require that Foo be cast to any specific type
If bar.GetType() Is GetType(DerivedExtendedB) Then
Dim barCast As DerivedExtendedB = DirectCast(bar, DerivedExtendedB)
' Perform task that requires Foo to be of type ClassB
ElseIf bar.GetType() Is GetType(DerivedExtendedC) Then
Dim barCast As DerivedExtendedC = DirectCast(bar, DerivedExtendedC)
' Perform task that requires Foo to be of type ClassC
End If
End Sub
What I'm looking for is advice outlining or describing a design pattern that can handle this situation. I've searched for quite a while, and have not been able to find any examples that solve this problem.
I realize that this may be somewhat of an "XY" problem. I'm working with existing code that simply assumes all instances are of the same derived type (when in fact some instances are of the other derived type). As such, the existing code does not work. To me what I've tried to outline above seems like the most straightforward path, but I'm open to alternative if this is just the wrong approach.
This pattern of type covariance in derived classes is the canonical reason for what is called in C++ the "Curiously Recurring Template Pattern" and has been called in .NET the "Curiously Recurring Generic Pattern." I believe it's also sometimes referred to as "F-Bounded Polymorphism" (not a computer scientist, so I might have the reference wrong).
You can write a base class like this:
Public Class Base(Of TDerived As Base)
Public Overridable Property foo As TDerived
End Class
And then use it like this:
Public Class MyDerived
Inherits Base(Of MyDerived)
End Class
Then, the derived class has a property foo whose type is MyDerived. No casting required by clients.
However, this has some limitations. It works best when you don't need to switch back and forth between derived and base. There is no one Base, so you can't declare instances of it. If you want to be able to declare something as Base, then you end up needing to fall back on a non-generic base class. This will still work well for certain usage patterns where you don't need to convert from base to derived, but otherwise you run right back into the casting problems you are trying to avoid.
Eric Lippert has written a bit about this pattern. He's always interesting to read, so I'd recommend looking up his commentary.
Another alternative to consider, if the generic approach doesn't work for you, is code generation. You can use T4 templates to process a compact description of what your code should be, and generate the code files from them. A long list of casts is less tedious if you only write the machinery to generate it, you don't write them all out explicitly.
I have been going crazy with trying to load multiple partial views in an MVC 5 app I am writing in VB.Net. Don't ask Why VB, the client insisted on it.
The app has a form that pulls from six lookup tables and I need to make a form that the administrator can edit the values of these lookup tables from.
The app has an edmx that the main form is built on and includes these six tables which worked very well for creating the main form, but I cannot find any way to create 6 partial views and load them into a single form.
I have tried How to Return partial view of another controller by controller? to load my partials and I have created separate classes and a View Model based on other posts.
Here is the code from the classes and view model I have tried with no luck.
My Classes.
Public Class CotListIems
Partial Public Class PlanList
Public Property Id As Integer
Public Property Superior As Decimal
Public Property Royal As Decimal
Public Property Maximo As Decimal
Public Property Manual As Boolean
Public Property ManSuperior As Nullable(Of Decimal)
Public Property ManRoyal As Nullable(Of Decimal)
Public Property ManMax As Nullable(Of Decimal)
End Class
Partial Public Class PlanRateList
Public Property Id As Short
Public Property Plan As String
Public Property Rate As Decimal
End Class
End Class
My View Model
Public Class AdminViewModel
Public Property PlanList As IEnumerable(Of PlanList)
Public Property PlanRateList As IEnumerable(Of PlanRateList)
End Class
My Controller
Function Admin(ByVal id As Integer?) As ActionResult
Dim viewModel = New AdminViewModel()
viewModel.PlanList = db.Plans.Include(Function(i) i.Id).Include(Function(c) c.Superior).Include(Function(c) c.Royal).Include(Function(c) c.Maximo).Include(Function(c) c.Manual).Include(Function(c) c.ManSuperior).Include(Function(c) c.ManRoyal).Include(Function(c) c.ManMax)
viewModel.PlanRateList = db.PlanRates.Include(Function(i) i.Id).Include(Function(c) c.Plan).Include(Function(c) c.Rate)
Return View(viewModel)
End Function
The Controller I added here is one that I tried to create, but I have also tried to scaffold one.
When I try to scaffold a new controller based on my view model I get Entity Type 'AdminViewModel' has no key defined. Define a key for this EntityType.
I cannot find any information on how to define a key for this, only for C#, all VB documentation seems to only work for anonymous types and looks to be static hard coded key values.
I'm really stuck here as it seems there are many ways and all I want to do is list the contents of six lookup tables on the same page with Edit links for each section to load them in another view.
Thanks, I know this is probably basic stuff, but it's confusing and very frustrating at the moment.
I am wondering what the following snippets code means. Specifically the section: "Of EntityType As {BusinessEntity, New})". I'm a little new to VB inheritance so some of the syntax is a little foregn to me. I understand that a base class is being used to add functionality to all business objects that inherit from it but the syntax is throwing me off a bit. Is there a name for this design pattern?
Public Class AppObjectBase(Of EntityType As {BusinessEntity, New})
Inherits BusinessObject(Of EntityType)
...
...
Public Class NavTreeObj
Inherits NavTree(Of NavTreeEntity)
End Class
Public Class NavTree(Of EntityType As {NavTreeEntity, New})
Inherits AppObjectBase(Of EntityType)
...
...
Do you know what the Of EntityType part on its own means? If not then you should read about generic types. As for the As {BusinessEntity, New} part, that means that EntityType must either be or inherit from the BusinessEntity type and it must also have a parameterless constructor. By specifying those constraints on the generic type parameter, you are able to access members of the BusinessEntity type and also invoke the constructor to create new instances within the method.
I have been seeing some odd behaviour in an entity that I have for which I created a partial class to override the ToSting Method and provide some basic property setting when a new instance of that entity is created (for example I might set an order date to 'Now') in a constructor.
This odd behaviour led me to look closely at the partial class and I was surprised to see that even when a set of pre existing records was being retrieved the constructor was being called for each retrieved record.
below is a very simple example of what I might have:
Partial Public Class Product
Public Sub New()
CostPrice = 0.0
ListPrice = 0.0
End Sub
Public Overrides Function ToString() As String
Return ProductDescription
End Function
End Class
I have two questions that arise from this:
1) is this normal behaviour in the Entity Framework if you add a partial class to which you add a constructor?
2) if not then I must assume that I have done something wrong, so what would be the correct way to
override the constructor to do things similar to the example I mentioned above?
Thanks for any insights that you can give me.
This is using EF 5.0 in a vb project
think to the sequence of events leading to the retrieval of an entity from the database. Basically it should be something like:
query the database
for each row of the query result give an entity
The giving is then as follow for each retrieved row:
create a new instance of the retrieved entity
populate this new instance with the value of the row
Well with each instance creation, the constructor is called.
I think you are mixing:
instance initialization where you "allocate" the object, and
business initialization where you enforce business logic
both may be done, at least partially, in the constructor.
new is always called when a class is first instantiated and if you do not explicitly declare a constructor then a default constructor will be created by the compiler.
Unless the class is static, classes without constructors are given a public default constructor by the C# compiler in order to enable class instantiation.
When defining POCO classes for Entity Framework the class must have a default constructor and EF will always call this default constructor whether you have explicitly defined it or the compiler did it for you.
If for any reason you have need to pass anything into the class when it is instantiated you can use the ObjectContext.ObjectMaterialized event.
I am using Entity Framework 4.1 code first+MVC3 and the inheritence stratagy that I use is TPC
I have the following classes
Public Class ObjectBase
<Key()>
Public Property Id As Integer
Public Property Description As String
End Class
Public Class Computer
Inherits ObjectBase
Public Property Computername As String
End Class
Public Class Book
Inherits ObjectBase
Public Property BookName As String
End Class
Public Class User
<Key()>
Public Property Id As Integer
Public Property Name As String
End Class
Public Class BorrowObject
<Key()>
Public Property Id As Integer
Public Property User As User
Public Property BorrowedObject as ObjectBase
End Class
Public Class BorrowComputerVM
<Key()>
Public Property Id As Integer
Public Property User As User
Public Property Computer as Computer
End Class
My questions are:
How do I do a query (using LINQ,
Entity SQL or other commonly used
way) to get all BorrowObjects where
BorrowedObject is of type Computer?
How do I map the result of the query
to the ViewModel called
"BorrowComputerVM" (used for
creating views only used for
borrowing a Computer).
Question 1 (and question 2) should be very simple, but I have allready spent hours on Google to find an answer with no result at all. The only thing I have found is that you can get all computers in ObjectBase by writing context.ObjectBase.OfType(Of Computer), and that does not help since you cannot write context.BorrowObjects.ObjectBase.OfType(Of Computer)
Please provide code samples in VB.NET (if you can), but more importantly: Please ensure that the codesamples you supply work without hours of modification!
I write it in C#:
How do I do a query (using LINQ, Entity SQL or other commonly used way)
to get all BorrowObjects where
BorrowedObject is of type
Computer?
var list = context.BorrowObjects.Include(b => b.BorrowedObject)
.Where(b => b.BorrowedObject is Computer)
.ToList();
You can omit the Include if you don't want to eager load the Computer.
How do I map the result of the query to the ViewModel called
"BorrowComputerVM" (used for creating
views only used for borrowing a
Computer).
var list = context.BorrowObjects
.Where(b => b.BorrowedObject is Computer)
.Select(b => new BorrowComputerVM
{
Id = b.Id,
User = b.User,
Computer = b.BorrowedObject as Computer
})
.ToList();
Includes are not necessary if you project into a new type: User and Computer will be loaded in the BorrowComputerVM also without explicit Include.
The is and as operators work indeed in LINQ to Entities.
This article describes a lot of configuration that's required for code-first TPC inheritance, as well as some special techniques you need to use. Has all of that already been done? If you've completed all the coding jujitsu described in the article, it seems like the query syntax or object structure shouldn't pose much of an obstacle to you.