I've been used to the old designer tools with it's code generation. The partial classes being generated, it was easy to add custom methods/properties
However with the new code generation tool on NuGet with fluent models, using partial classes doesn't seem to work. Nor does the MappingConfiguration class seem to support HasArtificalProperty, even though the documentation states otherwise.
What would be the best way to add custom properties/methods to the generated classes?
6 Answers, 1 is accepted
Thank you for your feedback about our new code generation tool.
You are right that the preview version is not generating partial entity classes. I will fix that for the next release. Meanwhile you can adjust one of the templates used for the code generation to suit your needs by adding the partial keyword in EntityClass.txt under Telerik.DataAccess.Fluent.CodeGeneration folder in your data model project. Here is the modified version:
01.
using
System;
02.
using
System.Collections.Generic;
03.
$extraNamespaces
04.
05.
namespace
$
namespace
06.
{
07.
public
partial
class
$entityType
08.
{
09.
public
$entityType()
10.
{
11.
}
12.
$primitiveProps
13.
$navProps
14.
}
15.
}
After saving the changes in the template, please run again the code generation to get new entity classes.
You can use .HasArtificialProperty() extension method by adding using Telerik.OpenAccess.Metadata.Fluent.Artificial; to your fluent mapping class. We have not added this using by default in order to keep your IntelliSense uncluttered until you need it.
Viktor Zhivkov
Telerik
Thanks for the reaction Viktor.
After generating the new partial classes we've added a new custom property to one of the classes. We also edited the "....metadatasource" class to add our custom property to the class:
configuration.HasArtificialProperty<String>("CustomPropertyName");
However it seems our custom property is seen as a real SQL column, to which we're getting the error "Telerik.OpenAccess.RT.sql.SQLException: Invalid column name 'ParentName'."
I am not sure if an artificial property is the correct type of property that you want to use.
If you want to have a custom property that is not bound to a column in the database then you need Transient property. Defining one is easy - after adding the property to a class you have to add a new line in the mapping configuration:
configuration.HasProperty(x => x.MyCustomProperty).AsTransient();
Artificial properties on the other hand and special persistent properties that are not known during compile time, but are added to your data model during runtime of the application. That's why there you are using Reflection-like string based syntax. For more information about artificial types and properties I suggest that you check our documentation articles.
If you need any further assistance do not hesitate to get back to us,
Regards,
Viktor Zhivkov
Telerik
Thanks Viktor, this is exactly what I was looking for.
However I have a follow-up question on this:
I'm now adding the custom properties to the "..MetaDatasource.generated" class, however being as this is a generated file all the custom properties are lost when the generation script is run.
Is there a way to keep the custom properties and generated properties seperated in the metadatasource class?
The quick way to have extensibility on fluent model level is to modify the code generation template to include a new definition and execution of partial method. Given that the generated code stays in one file and the custom code in another you can safely re-generate your data layer without losing your changes.
Below are the steps that will help you achieve the desired outcome:
- Modify ~Telerik.DataAccess.CodeGeneration\Templates\CS\MapConfiguration.txt by lines 15 and 20 from the code snippet below:
01.
public
MappingConfiguration<$type> $methodName()
02.
{
03.
var configuration =
new
MappingConfiguration<$type>();
04.
05.
configuration.MapType()
06.
.WithConcurencyControl(OptimisticConcurrencyControlStrategy.$concurrency)
07.
.ToTable(
"$tableName"
);
08.
09.
$identityProps
10.
11.
$primitiveProps
12.
13.
$associations
14.
15.
Customize$methodName(configuration);
16.
17.
return
configuration;
18.
}
19.
20.
partial
void
Customize$methodName(MappingConfiguration<$type> configuration);
- Run code generation script again
- Add a new partial extension class file to your generated FluentMetadataSource. Please make sure that the namespace and the class name of your partial extension are exactly the same as your FluentMetadataSource. Below you can see a sample extension that adds the definition of a transient property to an existing MappingConfiguration<Car>:
1.
partial
void
CustomizeGetCarConfiguration(MappingConfiguration<Car> configuration)
2.
{
3.
configuration.HasProperty(c => c.CalculatedTransientPropertyX).AsTransient();
4.
}
Regards,
Viktor Zhivkov
Telerik
We've been using this for a while now and it's been working great.
Hope the next update of the code generation tool will have this implemented.