"Cloning" EntityConnections and ObjectContexts in Entity Framework - c#

(This used to be a 2-part question, but since the second part is literally the important one, I decided to split this into two separate posts. See Using Serialization to copy entities between two ObjectContexts in Entity Framework for the second part.
I want to create a fairly generic "cloner" of databases for my entity model. Also, I might need to support different providers and such. I'm using ObjectContext API.
I am aware of this question already and the EntityConnectionStringBuilder MDSN documentation example, but I need to know if there is a programmatic way to obtain the values to initialize the Provider and Metadata properties of an EntityConnectionStringBuilder?
using (var sourceContext = new EntityContext()) {
var sourceConnection = (EntityConnection) sourceContext.Connection;
var targetConnectionBuilder = new EntityConnectionStringBuilder();
targetConnectionBuilder.ProviderConnectionString = GetTargetConnectionString();
targetConnectionBuilder.Provider = "System.Data.SqlClient"; // want code
targetConnectionBuilder.Metadata = "res://*/EntityModel.csdl|res://*/EntityModel.ssdl|res://*/EntityModel.msl"; // want code
using (var targetContext = new EntityContext(targetConnectionBuilder.ConnectionString)) {
if (!targetContext.DatabaseExists())
targetContext.CreateDatabase();
// how to copy all data from the source DB to the target DB???
}
}
That is, is there a way to fetch the
"System.Data.SqlClient"
"res://*/EntityModel.csdl|res://*/EntityModel.ssdl|res://*/EntityModel.msl"
from somewhere and not use literal values?

Metadata
You should be able to use res://*/ to tell Entity Framework to search for all .csdl, .ssdl and .msl files in the calling assembly. Alternatively, use res://assembly full name here/ to search in a specific assembly. Note that both these syntaxes will load all found files, which works fine until you have several .edmx in the same assembly, resulting in several CSDL/SSDL/MSL files (an .edmx file is basically a concatenation of those three files). More information on MSDN.
If you want more control, use Assembly.GetManifestResourceNames to list all resources in a given assembly, and match the .csdl/.ssdl/.msl resources manually together, then build your metadata string manually from those resource names.
Provider
The provider can be found in the SSDL file in the Provider attribute of the root node. Once you have the correct file name, Use GetManifestResourceStream and read the file as XML. The code should look like this:
using (var stream = assembly.GetManifestResourceStream("EntityModel.ssdl")) {
XDocument document = XDocument.Load(stream);
string provider = document.Root.Attribute("Provider").Value;
}

Related

How can I get the comments for symbols referenced by a CompletionItem?

Coming from this question, I've managed to get all CompletionItem instances available for a specific offset using completionService.GetCompletionsAsync(document, offset);.
So, after querying for completions of "MyString".Len, I get a CompletionItem for the Length method and can then, using the CompletionService, call service.GetDescriptionAsync(document, completionItem) to retrieve "int string.Length { get; }".
But, how can I get the comments for Length, e.g. "Gets the number of characters in the current String object."? And, if easily possible, other information regarding potential overloads?
Assuming that you're adding references to the assemblies using
MetadataReference.CreateFromFile method, you should pass an DocumentationProvider instance as an additional parameter, like this:
MetadataReference.CreateFromFile(path, MetadataReferenceProperties.Assembly, new MyDocumentationProvider(path));
DocumentationProvider is an abstract class, we ended up implementing our own by overriding GetDocumentationForSymbol method and locating appropriate XML node inside XML document.
Looking at Roslyn source code, there is XmlDocumentationProvider class which has an abstract method GetSourceStream (where you're supposed to pass a content of .xml file that stores documentation for .NET assemblies).
Please note that for this feature to work there should be an .xml file with descriptions file next to the assembly (which is normally produced from the source code when you have compile an assembly with Documentation File option set).
For .NET assemblies these files are included as part of SDK, and normally can be found at:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\vxxx
We use this approach in our Roslyn-based parsers in our AlterNET Studio product. You may find a bit more information about these parsers here.
GetDescriptionAsync can only return a number of overloads, to get list of overloads available at the same position you might need to use Recommender API like this:
var model = document.GetSemanticModelAsync().Result
var symbols = Microsoft.CodeAnalysis.Recommendations.Recommender.GetRecommendedSymbolsAtPositionAsync(model, pos, workspace).Result;
This API will return a separate symbol for every overload.
We asked a while ago whether it's possible to retrieve additional information (such as underlying symbol) from CompletionItem and the short answer is no. You may refer to the discussion here:
https://github.com/dotnet/roslyn/issues/57677

ServiceStack's RedisTypedClient - Can you use strings to define the type?

I'm trying to figure out if there is any way to create a RedisClient that has the functionality of a RedisTypedClient but able to define the URN key with a simple string instead of passing in a type. For example, at the moment we're creating the IRedisTypedClient like so:
var redisProjectClient = _redisClientsManager.GetClient().As<Project>()
We can then store/retrieve related entities based on types that we know about:
var files = redisProjectClient.GetRelatedEntities<File>(projectId);
However, we're wanting to manage simple JSON payloads of objects from external services (fetched by HTTP API endpoints). These payload objects will be types that we won't know about in c# but will provide schema's/type names that we want to be able to use to manage the relationships like we do in the redis typed client. I can't see if this is currently possible without having to manually manage all of the extra stuff that makes the typed clients so good:
Id listing for entities of that type
The ability to retrieve/update entities related to an object
GetNextSequence for next Id
These aren't available in a flat IRedisClient so I want to do something like this:
var file = "{...}" // JSON object provided by external service
// We will know it's a "Project" type with a "projectID" from the JSON payload data:
var redisProjectClient = _redisClientsManager.GetClient().As("Project");
redisProjectClient.StoreRelatedEntities("File", projectId, file);
// ...
var files = redisProjectClient.GetRelatedEntities("File", projectId);
Any idea if this is possible or how to create this type of client?
RedisTypedClient - Can you use strings to define the type?
No the Typed clients only works with Types, not unknown data structures, you'll need to store any arbitrary JSON payloads using the string IRedisClient.
To maintain the relationships you can store them in Redis sets as described in this previous answer which is what the StoreRelatedEntities() API does behind the scenes where it stores the entities using StoreAll() as normal but also maintains the related entities in an index Set using the urn (e.g. urn:File:x) as the identifier that each entity is stored against.
GetRelatedEntities() then reads all ids maintained in the "relationship set index" and uses GetValues() to fetch all entities by urns.

Object Teletransport

I have a object, better, a class. It is like a win form, with the parts:
class.cs, class.Designer.cs and the last class.Resx
It is an XtraReport, so what I'm doing is to get this object and serialize it into a xml file that holds enough information about its controls. The xml generated is used on another project, that uses just the xml. The problem is that it is not enough, despite the xml having all information, it still needs the origin object to resolve the controls properly. Basically:
Saving the Xml - First Solution(C# solution):
var originalReport = new MyCompleteReportDrawInDesignerMode();
original.SaveLayoutToXml(#"c:\FileToBeSerializedAndUsedInAnotherProject");
Consuming the Xml - Another solution(C# Solution)
var genericClass = new GenericClass();
genericClass.LoadLayoutFromXml(#"C:\FileGeneratedByDeserializedXML");
Both classes are child from XtraReports:
public class MyCompleteReportDrawInDesignerMode : XtraReport
public class GenericClass : XtraReport
this doest not work, since the Another Solution does not have a clue about MyCompleteReportDrawInDesignerMode. So i thought, why not teletransport the whole object and make it happen
//Build the object
var generator = GetObjectFromText(text);
//Resolve the dependecy check
var objectGenerated = generator.ResolveAssembly();
But I have no clue how to do it or if it is viable. Any thoughts ?
Update:
I wanna store the class implementation in the database and rebuild it from another application, since the xml transformation is causing information loss.
Let me introduce a little more deeper context. We are building a reporting server application. The process is basically:
1 - Desginer the XtraReport in designer mode, set the fields databindings, set the xrsubreports reportsource if any
2 - Make a xml file from it and save in local C:\ hard driver.
3 - In another application, the user uploads this file and serialize it into varbinary.
4 - The client side receives this serialized xml and restore it, then it trys to load into a generic XtraReport class.
So I would have to create and bound this assemblys at runtime, since we cannot relase a new version of our product every new report we built.
You need to make the MyCompleteReportDrawInDesignerMode class known by both solutions.
Make a separate class library assembly (separate project) that defines MyCompleteReportDrawInDesignerMode. This assembly (DLL) can then be referenced by both applications; the one that writes the report to an XML file and the one that reads this file and recreates the report.
the solution found was to create a class library visual studio solution, then we design the report, the subreports, and compile the all thing, and serialize the dll into a varbinary column in sql server. The dll is small, about 100 kbytes, so no problem.
After serialized into the database, the other application can consume the dll. In the same table, we put the namespace and class name from the main report, so you can create a instance at runtime, fill the datasource and print. I found that the xml serialization only works on the most recent devexpress versions, like: 13.1.10.
Here is the code:
Assembly local =
Assembly.LoadFile(#"C:\TempReports\5a788bc0-3e70-4f8b-8fa9-f180d23c4f03.dll");
Type t = _local.GetType("Relatórios_Teste.Reports.FluxoCaixa");
object test = Activator.CreateInstance(t);
var report = (XtraReport) test;
var controls = report.AllControls<XRSubreport>();
foreach (var control in controls)
{
if (control.Name.Equals("sub_detail"))
{
control.ReportSource.DataSource = GetSource();
control.ReportSource.DataMember = #"sp_test";
}
}
report.ShowPreview();

EntLib Validation: Localization without resources - Validation from configuration

I would like to use my own localization implementation instead of the default resource file system the framework provides. I need also to configure the validators in a configuration file.
My problem is that I don't know how to access the Validator objects to change their message templates after I have instantiated the ConfigurationValidatorFactory. I can create a validator for my object like this:
var cfgSrc = new FileConfigurationSource("Validations.xml");
var factory = ConfigurationValidatorFactory.FromConfigurationSource(cfgSrc);
Validator val = factory.CreateValidator<MyObj>();
, but 'val' above is then of type GenericValidatorWrapper and has no properties to access the 'true validator' instances.
After validation I can see the true Validator instances, but then it is too late to change their template text. The final message (containing the limit values) has then already been created and changing the template won't re-create the message.
Any suggestions?
Enterprise Library version is 5.
You might be able to use reflection to modify the validator properties that you are interested in. But that is really messy and Kludgy.
What if you simply replaced the message text on the validation results after validation?
The message in the configuration file could be a place holder (e.g. NAME_INVALID_LENGTH) and you could replace that with your actual text.
var cfgSrc = new FileConfigurationSource("Validations.xml");
var factory = ConfigurationValidatorFactory.FromConfigurationSource(cfgSrc);
Validator val = factory.CreateValidator<MyObj>();
MyObj myObj = new MyObj();
myObj.Name = "Swiper McFoxy";
ValidationResults results = new ValidationResults();
foreach (ValidationResult result in val.Validate(myObj))
{
results.AddResult(
new ValidationResult(
GetMessage<MyObj>(result.Message, new CultureInfo("en")),
result.Target,
result.Key,
result.Tag,
result.Validator,
result.NestedValidationResults));
}
Update
OK, if you need the template text you can investigate poking around via reflection but that still looks really messy.
Given your requirements (configuration file, maintain templates) what I would probably do would be to create multiple configuration files each with the template text you want.
That's a bit of a maintenance nightmare so I would refine that idea to:
Create my configuration file Validations.xml and instead of putting my templated text in I would use a unique placeholder for each message (e.g. NAME_INVALID_LENGTH but even more unique-ish).
Then I would write a small piece of code/tool that would, for every locale you are supporting, replace the unique placeholder with the locale specific templated text. And copy the resultant file to a locale specific folder under the OutDir (e.g. bin\debug\en-US\Validations.xml). This is similar to how .NET deploys satellite assemblies so it is not that far a stretch.
Run the tool above as a post-build step. The tool can flag placeholders that it can't find so that it gets reported during the build. This should help keep the placeholders and the template text in sync.
Modify your code to use the locale specific configuration file:
CultureInfo culture = new CultureInfo("en-us");
var cfgSrc = new FileConfigurationSource(culture.Name + #"\Validations.xml");
var factory = ConfigurationValidatorFactory.FromConfigurationSource(cfgSrc);
Validator val = factory.CreateValidator<MyObj>();
You can abstract the culture specific code behind a helper method so that it's easier to read and maintain. e.g. GetValidationConfigurationSource(culture).

Fluent Nhibernate external configuration

All examples of fluent nhibernate make such(or similar) call:
c.AddMappingsFromAssembly(typeof(Product).Assembly);
I don't want tu use "typeof(Product).Assembly" as i don't want to have reference to my domain project here ("Procuct" class). In ordinary NHibernate I would just create hbm.xml files and make following entry in web.config:
<mapping assembly="TestingFluentHN"/>
but this entry does not work with FluentNHibernate. Is there an elegant way of providing assemblies in my session-building method? Preferably from configuration file.
Resources:
Context of unwanted code/dependency:
static NHSessionManager()
{
Configuration c = new Configuration();
//change following to sth that does not need refernce to domain
c.AddMappingsFromAssembly(typeof(Product).Assembly);
c.Configure();
sessionFactory = c.BuildSessionFactory();
}
My first idea was to read assemblies names from appSettings and load them:
var assembliesToMap = new List<string>();
foreach (var assemblyName in assembliesToMap)
{
var assembly = Assembly.LoadFile(assemblyName);
c.AddMappingsFromAssembly(assembly);
}
but that is my last option. I'm looking for sth build in fluent nhibernate.
I'm not aware of anything built into fluent nhibernate that will do what you want. You'll probably need to use the method you laid out in the end of your question.
I'm not sure if I'm just not getting the right picture of how your application is laid out, but the whole idea seems a bit misguided. You will need to take a dependency on the domain objects to query the session anyway, and it seems likely that this would be in the same assembly as the session factory's creation. If not, you may consider using dependency injection to provide a session manager (from a project that is aware of the domain objects).
If I'm missing something please let me know.

Categories