Is it possible to use ASP.NET Dynamic Data and SubSonic 3? - subsonic

Is it possible to use ASP.NET Dynamic Data with SubSonic 3 in-place of Linq to SQL classes or the Entity Framework? MetaModel.RegisterContext() throws an exception if you use the context class that SubSonic generates. I thought I remembered coming across a SubSonic/Dynamic Data example back before SubSonic 3 was released but I can't find it now. Has anyone been able to get this to work?

I just got Subsonic 3.0.0.4 ActiveRecord working last night in Visual Studio 2010 with my SQLite database after a little bit of work and I've tried to document the steps taken here for your benefit.
Start by adding a New Item -> WCF Data Service to the project you're using to host your webapp/webservices then modify it similar to my PinsDataService.svc.cs below:
public class PinsDataService : DataService<PINS.Lib.dbPINSDB>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.UseVerboseErrors = true;
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
At this point your Dynamic Data Service would probably be working if you matched all the database naming conventions perfectly but I didn't have that kind of luck. In my ActiveRecord.tt template I had to prepend the following two lines before the public partial class declarations:
[DataServiceKey("<#=tbl.PrimaryKey #>")]
[IgnoreProperties("Columns")]
public partial class <#=tbl.ClassName#>: IActiveRecord {
I then added references to System.Data and System.Data.Services.Client followed by the inclusion of using statements for using System.Data.Services and using System.Data.Services.Common at the top of the ActiveRecord.tt template.
The next step was to use the IUpdateable partial class implementation from this blog post http://blogs.msdn.com/aconrad/archive/2008/12/05/developing-an-astoria-data-provider-for-subsonic.aspx and change the public partial class dbPINSDB : IUpdatable to match my subsonic DatabaseName declared in Settings.ttinclude
Then to consume the data in a separate client app/library I started by adding a 'Service Reference' named PinsDataService to the PinsDataService.svc from my client app and went to town:
PinsDataService.dbPINSDB PinsDb =
new PinsDataService.dbPINSDB(new Uri("http://localhost:1918/PinsDataService.svc/"));
PinsDataService.Alarm activeAlarm =
PinsDb.Alarms.Where(i => i.ID == myAA.Alarm_ID).Take(1).ElementAt(0);
Note how I'm doing a Where query that returns only 1 object but I threw in the Take(1) and then ElementAt(0) because I kept getting errors when I tried to use SingleOrDefault() or First()
Hope this helps--also, I'm already aware that dbPINSDB is a really bad name for my Subsonic Database ;)

Related

ServiceStack.OrmLite equivalent of Single/SingleOrDefault from Entity Framework

Currently when using OrmLite library from ServiceStack if I want single entity selected I do:
AppUser user = db.First<AppUser>(q => q.Id == id);
However since Single is more precise (obviously I want exception thrown if somehow multiple users with same id ended up in database) I was wondering if there is overload that I can use. Currently when I do db.Single I just get that overload with manual filtering:
public static T SingleOrDefault<T>(this IDbConnection dbConn, string filter);
OK, I found what the issue is - the version I'm using (3.9.71) doesn't have that overload - it was added later:
https://github.com/ServiceStack/ServiceStack.OrmLite/commit/f2f5f80f150f27266bdcaf81b77ca60b62897719#diff-e9a84724e6a8315ec7f7fc5a5512a44b
Seems I'll need to extend that class from within my code.

How to use ObjectContext with Model Builder?

Is there a way we can use ObjectContext with DbContext's ModelBuilder? We don't want to use POCO because we have customized property code that does not modify entire object in update, but only update modified properties. Also we have lots of serialisation and auditing code that uses EntityObject.
Since poco does create a proxy with EntityObject, we want our classes to be derived from EntityObject. We don't want proxy. We also heavily use CreateSourceQuery. The only problem is EDMX file and its big connection string syntax web.config.
Is there any way I can get rid of EDMX file? It will be useful as we can dynamically compile new class based on reverse engineering database.
I would also like to use DbContext with EntityObject instead of poco.
Internal Logic
Access Modified Properties in Save Changes which is available in ObjectStateEntry and Save them onto Audit with Old and New Values
Most of times we need to only check for Any condition on Navigation Property for example
User.EmailAddresses.CreateSourceQuery()
.Any( x=> x.EmailAddress == givenAddress);
Access Property Attributes, such as XmlIgnore etc, we rely heavily on attributes defined on the properties.
A proxy for a POCO is a dynamically created class which derives from (inherits) a POCO. It adds functionality previously found in EntityObject, namely lazy loading and change tracking, as long as a POCO meets requirements. A POCO or its proxy does not contain an EntityObject as the question suggests, but rather a proxy contains functionality of EntityObject. You cannot (AFAIK) use ModelBuilder with EntityObject derivatives and you cannot get to an underlying EntityObject from a POCO or a proxy, since there isn't one as such.
I don't know what features of ObjectContext does your existing serialisation and auditing code use, but you can get to ObjectContext from a DbContext by casting a DbContext to a IObjectContextAdapter and accessing IObjectContextAdapter.ObjectContext property.
EDIT:
1. Access Modified Properties in Save Changes which is available in ObjectStateEntry and Save them onto Audit with Old and New Values
You can achieve this with POCOs by using DbContext.ChangeTracker. First you call DbContext.ChangeTracker.DetectChanges to detect the changes (if you use proxies this is not needed, but can't hurt) and then you use DbCotnext.Entries.Where(e => e.State != EntityState.Unchanged && e.State != EntityState.Detached) to get DbEntityEntry list of changed entities for auditing. Each DbEntityEntry has OriginalValues and CurrentValues and the actual Entity is in property Entity.
You also have access to ObjectStateEntry, see below.
2. Most of times we need to only check for Any condition on Navigation Property for example:
User.EmailAddresses.CreateSourceQuery().Any( x=> x.EmailAddress == givenAddress);
You can use CreateSourceQuery() with DbContext by utilizing IObjectContextAdapter as described previously. When you have ObjectContext you can get to the source query for a related end like this:
public static class DbContextUtils
{
public static ObjectQuery<TMember> CreateSourceQuery<TEntity, TMember>(this IObjectContextAdapter adapter, TEntity entity, Expression<Func<TEntity, ICollection<TMember>>> memberSelector) where TMember : class
{
var objectStateManager = adapter.ObjectContext.ObjectStateManager;
var objectStateEntry = objectStateManager.GetObjectStateEntry(entity);
var relationshipManager = objectStateManager.GetRelationshipManager(entity);
var entityType = (EntityType)objectStateEntry.EntitySet.ElementType;
var navigationProperty = entityType.NavigationProperties[(memberSelector.Body as MemberExpression).Member.Name];
var relatedEnd = relationshipManager.GetRelatedEnd(navigationProperty.RelationshipType.FullName, navigationProperty.ToEndMember.Name);
return ((EntityCollection<TMember>)relatedEnd).CreateSourceQuery();
}
}
This method uses no dynamic code and is strongly typed since it uses expressions. You use it like this:
myDbContext.CreateSourceQuery(invoice, i => i.details);

How does Database.SetInitializer actually work? (EF code-first create database and apply migrations using several connection strings)

I am trying to write a method to create a database and run migrations on it, given the connection string.
I need the multiple connections because I record an audit log in a separate database.
I get the connection strings out of app.config using code like
ConfigurationManager.ConnectionStrings["Master"].ConnectionString;
The code works with the first connection string defined in my app.config but not others, which leads me to think that somehow it is getting the connection string from app.config in some manner I don't know.
My code to create the database if it does not exist is
private static Context MyCreateContext(string ConnectionString)
{
// put the connection string where the factory method can get it
AppDomain.CurrentDomain.SetData("ConnectionString", ConnectionString );
var factory = new ContextFactory();
// I know I need this line - but I cant see how what follows actually uses it
Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context,DataLayer.Migrations.Configuration>());
var context = factory.Create();
context.Database.CreateIfNotExists();
return context
}
The code in the Migrations.Configuration is
Public sealed class Configuration : DbMigrationsConfiguration<DataLayer.Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
The context factory code is
public class ContextFactory : IDbContextFactory<Context>
{
public Context Create()
{
var s = (string)AppDomain.CurrentDomain.GetData("ConnectionString");
return new Context(s);
}
}
Thus I am setting the connection string before creating the context.
Where can I be going wrong, given that the connection strings are all the same except the database name, and the migration code runs with one connection string, but doesnt run with others?
I wonder if my problem is to do with understanding how How does Database.SetInitializer actually works. I am guessing something about reflection or generics. How do i make the call to SetInitializer tie tie to my actual context?
I have tried the following code but the migrations do not run
private static Context MyCreateContext(string ConnectionString)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, DataLayer.Migrations.Configuration>());
var context = new Context(ConnectionString);
context.Database.CreateIfNotExists();
}
This question appears to be related
UPDATE:
I can get the migrations working if I refer to the connection string using
public MyContext() : base("MyContextConnection") - which points to in the config
I was also able to get migrations working on using different instances of the context, if I created a ContextFactory class and passed the connection to it by referencing a global. ( See my answer to the related question link )
Now I am wondering why it has to be so hard.
I'm not sure exactly as to what the problems are you facing, but let me try
The easiest way to provide connection - and be sure it works that way...
1) Use your 'DbContext' class name - and define a connection in the app.config (or web.config). That's easiest, you should have a connection there that matches your context class name,
2) If you put it into the DbContext via constructor - then be consistent and use that one. I'd also suggest to 'read' from config connections - and again name it 'the same' as your context class (use the connection 'name', not the actual string),
3) if none is present - EF/CF makes the 'default' one - based on your provider - and your context's class name - which usually isn't what you want,
You shouldn't customize with initializers for that reason -
initializers should be agnostic and serve other purpose - setup
connection in the .config - or directly on your DbContext
Also check this Entity Framework Code First - How do I tell my app to NOW use the production database once development is complete instead of creating a local db?
Always check 'where your data' goes - before doing anything.
For how the initializer actually works - check this other post of mine, I made a thorough example
How to create initializer to create and migrate mysql database?
Notes: (from the comments)
Connection shouldn't be very dynamic - config is the right place for it to be, unless you have a good reason.
Constructor should work fine too.
CreateDbIfNotExists doesn't work well together with the 'migration' initializer. You can just use the MigrateDatabaseToLatestVersion initializer. Don't 'mix' it
Or - put something like public MyContext() : base("MyContextConnection") - which points to <connectionStrings> in the config
To point to connection - just use its 'name' and put that into constructor.
Or use somehting like ConfigurationManager.ConnectionStrings["CommentsContext"].ConnectionString
Regarding entertaining 'multiple databases' with migrations (local and remote from one app) - not exactly related - but this link - Migration not working as I wish... Asp.net EntityFramework
Update:
(further discussion here - Is adding a class that inherits from something a violation of the solid principles if it changes the behavior of code?)
It is getting interesting here. I did manage to reproduce the problems you're facing actually. Here is a short breakdown on what I think it's happening:
First, this worked 'happily':
Database.SetInitializer(new CreateAndMigrateDatabaseInitializer<MyContext, MyProject.Migrations.Configuration>());
for (var flip = false; true; flip = !flip)
{
using (var db = new MyContext(flip ? "Name=MyContext" : "Name=OtherContext"))
{
// insert some records...
db.SaveChanges();
}
}
(I used custom initializer from my other post, which controls migration/creation 'manually')
That worked fine w/o an Initializer. Once I switched that on, I ran into some curious problems.
I deleted Db-s (two, for each connection). I expected to either not work, or create one db, then another in the next pass (like it did, w/o migrations, just 'Create' initializer).
What happened, to my surprise - is it actually created both databases on the first
pass ??
Then, being a curious person:), I put breakpoints on the MyContext ctor, and debugged through the migrator/initializer. Again empty/no db-s etc.
It created first instance on my call within the flip. Then on the first access to 'model', it invoked the initializer. Migrator took over (having had no db-s). During the migrator.Update(); it actually constructs the MyContext (I'm guessing via generic param in Configuration) - and calls the 'default' empty ctor. That had the 'other connection/name' by default - and creates the other Db all as well.
So, I think this explains what you're experiencing. And why you had to create the 'Factory' to support the Context creation. That seems to be the only way. And setting some 'AppDomain' wide 'connection string' (which you did well actually) which isn't 'overriden' by default ctor call.
Solution that I see is - you just need to run everything through factory - and 'flip' connections in there (no need for static connection, as long as your factory is a singleton.
You can supply a configuration in the MigrateDatabaseToLatestVersion constructor.
If you set the initializer in the DbContext you can also pass a 'true' to use the current connection string.

ServiceStack - generate ASP.NET webservice -reference issue

I am using the very excellent servicestack libaries and trying to generate a ASP.NET web-service reference (old style not WCF) from within VS2010 across my servicestack WSDL - Soap11. To nicely wrap the service WSDL.
The DTO's are in a seperate assembly/namespace (My.WS.DTO) from the AppHost/services and are following the request/response naming convention.. when I try to generate the reference through visual studio I get the following error in VS.
Custom tool error: Unable to import WebService/Schema. Unable to import binding 'BasicHttpBinding_ISyncReply' from namespace 'http://schemas.servicestack.net/types'. Unable to import operation 'GetMyDetails'. The element 'http://schemas.servicestack.net/types:GetMyDetails' is missing.
NOTE: GetMyDetails is just the first service that appears in the list - so I dont believe this is the problem.
I have tried adding the assembly namespace in the AppHost file using
EndpointHostConfig.Instance.WsdlServiceNamespace = "My.WS.DTO"; and this just causes the same generation error (as above) but with 'My.WS.DTO' instead of 'http://schemas.servicestack.net/types'.
I assume it is perhaps some sort of referencing problem but any guidance as to what I might be doing wrong would be great.
cheers
I don't know if this is still an issue for you but I had a similar problem and found that I had not decorated one of my DTOs with [DataContract] and [DataMember] attributes, as described on the SOAP Support wiki page. Once you have added these to your DTO it will be declared in the type section of the WSDL.
Have a look at using [DataContract (Namespace = "YOUR NAMESPACE")] on top of your DTO's. This is how my objects are referenced.
[DataContract(Namespace = "My.WS.DTO")]
public class Account{
}
I also use this in my service model. [System.ServiceModel.ServiceContract()] and [System.ServiceModel.OperationContract()]
[System.ServiceModel.ServiceContract()]
public class SendGetAccountResponseService : IService<SendGetAccountNotification>
{
#region IService implementation
[System.ServiceModel.OperationContract()]
public object Execute (SendGetAccountNotification request)
{
Console.WriteLine ("Reached");
return null;
}
#endregion
}
Hope this helps / solves your problem.
I know this is an old question, but I had to add SOAP support for a 3rd party that refused to support REST very recently to my ServiceStack implementation so it could still be relevant to other people still having this issue.
I had the same issue you were having:
Unable to import binding 'BasicHttpBinding_ISyncReply'...
And like mickfold previously answered I needed to add [DataContract] and [DataMember] to my class definitions and their properties.
But I also had to add the following to my AssemblyInfo.cs file before the error went away for me:
[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "My Type Namespace")]
I assume that you will need one of these lines for every single namespace where you have a type declared, which based upon the original question above would be My.WS.DTO.

Subsonic Deeploads: Is This Supported?

It could very well be that I'm just missing the correct vernacular in this space, but I'm looking for a particular piece of functionality in SubSonic. In NetTiers it was called a "DeepLoad". A deep load runs to the database and fetches many objects (ie. fetch this OrderDetail and all of it's LineItems) in one database call.
Again, I want to run to the data store once an build up a potentially dense object graph or related items populated by the data store.
How do I do this in SubSonic and what is it called in SubSonic?
You can do this in SubSonic 3.0 (not yet released, but almost there...) using IQueryable with lazy loading:
var db=new NorthwindDB();
var order=db.Orders.Where(x=>.xID==20).SingleOrDefault();
Assert.Equal(3,order.OrderDetails.Count());
if you're not on 3 (which requires .net 3.5) you can do this with Active record as Paul mentions - but it will make two calls.
There is no eager loading, and DeepSave in ActiveRecord only calls Save.
Here is an example with Northwind Order class foreign key method.
[Test]
public void SelectOrderDetails()
{
Order order = new Order(10250);
OrderDetailCollection details = order.OrderDetails();
Assert.IsTrue(details.Count == 3);
}

Resources