This is my migration and seeding code:
internal sealed class Configuration : DbMigrationsConfiguration<AuthDb>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "Service.DAL.AuthDb";
}
}
public class CreateOrRunMigrations: CreateDatabaseIfNotExists<AuthDb>
{
public override void InitializeDatabase(AuthDb context)
{
base.InitializeDatabase(context);
var migrator = new DbMigrator(new Migrations.Configuration());
migrator.Update();
}
protected override void Seed(AuthDb context)
{
base.Seed(context);
// add Default product and company
}
}
The context is constructed this way
public class AuthDb : DbContext
{
public AuthDb() : base("name=xxx")
{
Database.SetInitializer(new CreateOrRunMigrations());
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
Configuration.AutoDetectChangesEnabled = true;
}
}
What I want is:
When the database is created first time, the seeding data is added.
When I make a change in the model, the migration code will apply the changes to the database automatically.
When I make a change (e.g. Company), and use update_database to add a migration in the console, the migration file was created. But when the code is run, I got an error complaining that my model and database doesn't match any more.
Of course it doesn't match as I just made a change and I was hoping that the migration will apply the change. However, it didn't. What I did wrong?
Your initializer derives from CreateDatabaseIfNotExists so it's only going to run when the database does not exist. Try making it derive from MigrateDatabaseToLatestVersion:
public class CreateOrRunMigrations: MigrateDatabaseToLatestVersion<AuthDb>
{
// no need for InitializeDatabase override since that's what this initializer does...
protected override void Seed(AuthDb context)
{
base.Seed(context);
// add Default product and company
}
}
Related
I need some help here. I created a custom report invoice design for PSAProjInvoice.
I did duplicate PSAProjInvoice and worked on a already made design.
Created a Controller and PrintMgmtDocTypeHandler class.
Created outputitem extension and redirected it to my ProjInvoiceController
In axapta in ProjFormletterParameters form parameters it shows me name of my custom report but when I go to project invoices and try to make a look at the invoice I just get a error: Unable to find the report design PSAProjInvoiceSZM.ReportPL.
class PSAProjInvoiceSZM
{
[PostHandlerFor(classStr(PSAProjAndContractInvoiceController),
staticMethodStr(PSAProjAndContractInvoiceController, construct))]
public static void ReportNamePostHandler(XppPrePostArgs arguments)
{
PSAProjAndContractInvoiceController controller = arguments.getReturnValue();
controller.parmReportName(ssrsreportstr(PSAprojinvoiceSZM, Report));
}
}
I think that it's a problem with my controller class because I actually have no idea how it should look like. Tried to make one based on salesinvoice tutorial found on microsoft docs but it didn't help me at all.
Tried to make it based on this article:
https://blogs.msdn.microsoft.com/dynamicsaxbi/2017/01/01/how-to-custom-designs-for-business-docs/
My Controller:
class ProjInvoiceControllerSZM extends PSAProjAndContractInvoiceController
{
public static ProjInvoiceControllerSZM construct()
{
return new ProjInvoiceControllerSZM();
}
public static void main(Args _args)
{
SrsReportRunController formLetterController =
ProjInvoiceControllerSZM::construct();
ProjInvoiceControllerSZM controller = formLetterController;
controller.initArgs(_args);
Controller.parmReportName(ssrsReportStr(PSAProjInvoiceSZM, Report));
/* if (classIdGet(_args.caller()) ==
classNum(PurchPurchOrderJournalPrint))
{
formLetterController.renderingCompleted +=
eventhandler(PurchPurchOrderJournalPrint::renderingCompleted);
}*/
formLetterController.startOperation();
}
protected void outputReport()
{
SRSCatalogItemName reportDesign;
reportDesign = ssrsReportStr(PSAProjInvoiceSZM,Report);
this.parmReportName(reportDesign);
this.parmReportContract().parmReportName(reportDesign);
formletterReport.parmReportRun().settingDetail().parmReportFormatName(reportDesign);
super();
}
}
I'm trying to program a custom DeploymentPlanExecutor using Microsofts DacFx 3.0 but the OnExecute-Method is never called.
If I use an identical DeploymentPlanModifier instead, OnExecute() is called as expected.
No matter whether I add the Executor, the Modifier, or both, the DAC actually is successfully deployed to the Database.
The Executor seems to be recognized during the Deployment since OnApplyDeploymentConfiguration() is called
Unfortunately I wasn't able to find any examples that use an DeploymentPlanExecutor (only examples with DeploymentPlanModifier) and the documentation of DacFx does not help at all.
My question is, why is OnExecute() in the DeploymentPlanExecutor not called and how can I fix this?
The code for my DeploymentPlanExecutor and DeploymentPlanExecutor:
using System.Collections.Generic;
using Microsoft.SqlServer.Dac.Deployment;
namespace DacTest
{
// The executor that does not work as expected
[ExportDeploymentPlanExecutor(ContributorId, "1.0.0.0")]
public class Executor : DeploymentPlanExecutor
{
public const string ContributorId = "DacTest.Executor";
protected override void OnApplyDeploymentConfiguration(DeploymentContributorContext context, ICollection<DeploymentContributorConfigurationStream> configurationStreams)
{
// Called
}
protected override void OnEstablishDeploymentConfiguration(DeploymentContributorConfigurationSetup setup)
{
// Not called
}
protected override void OnExecute(DeploymentPlanContributorContext context)
{
// Not called!
}
}
// The modifier that does work as expected
[ExportDeploymentPlanModifier(ContributorId, "1.0.0.0")]
public class Modifier : DeploymentPlanModifier
{
public const string ContributorId = "DacTest.Modifier";
protected override void OnApplyDeploymentConfiguration(DeploymentContributorContext context, ICollection<DeploymentContributorConfigurationStream> configurationStreams)
{
// Called
}
protected override void OnEstablishDeploymentConfiguration(DeploymentContributorConfigurationSetup setup)
{
// Not called
}
protected override void OnExecute(DeploymentPlanContributorContext context)
{
// Called!
}
}
}
The code calling the deployment (has to be in a different assembly):
using (DacPackage dacpac = DacPackage.Load(#"C:\Temp\dac.dacpac"))
{
DacDeployOptions dacDeployOptions = new DacDeployOptions();
dacDeployOptions.AdditionalDeploymentContributors = Executor.ContributorId; // + ";" + Modifier.ContributorId;
DacServices dacServices = new DacServices(connectionString);
dacServices.Deploy(dacpac, databaseName, true, dacDeployOptions);
}
The problem was, that you have to explicitly tell DacFx to use Executors. Modifiers are enabled by default though.
dacDeployOptions.RunDeploymentPlanExecutors = true;
I have a following problem. I register my components and initialize them in Unity like this (example is for a Console application):
public class SharePointBootstrapper : UnityBootstrapper
{
...
public object Initialize(Type type, object parameter) =>
Container.Resolve(type,
new DependencyOverride<IClientContext>(Container.Resolve<IClientContext>(parameter.ToString())),
new DependencyOverride<ITenantRepository>(Container.Resolve<ITenantRepository>(parameter.ToString())));
public void RegisterComponents()
{
Container
.RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString())
.RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString())
.RegisterType<ITenantRepository, DocumentDbTenantRepository>(SharePointClientContext.Online.ToString())
.RegisterType<ITenantRepository, JsonTenantRepository>(SharePointClientContext.OnPremise.ToString());
}
}
public enum SharePointClientContext
{
Online,
OnPremise
}
class Program
{
static void Main(string[] args)
{
...
bootstrap.RegisterComponents();
var bla = bootstrap.Initialize(typeof(ISharePointManager), SharePointClientContext.Online);
}
}
So, I register my components in MVC, WCF, Console etc. once with RegisterComponents() and initialize them with Initialize().
My question is, if I want to initialize specific named registration at runtime, from e.g. user input, can it be done otherwise as the code presented (with InjectionFactory or similar)?
This code works fine, but I'm not happy with its implementation. I have a feeling that it could be written in RegisterComponents() instead of Initialize() so that it accepts a parameter of some type, but I don't know how to do it.
Or, is maybe my whole concept wrong? If so, what would you suggest? I need to resolve named registration from a parameter that is only known at runtime, regardless of the technology (MVC, WCF, Console, ...).
Thanks!
Instead of doing different registrations, I would do different resolves.
Let's say that you need to inject IClientContext, but you want different implementations depending on a runtime parameter.
I wrote a similiar answer here. Instead of injecting IClientContext, you could inject IClientContextFactory, which would be responsible for returning the correct IClientContext. It's called Strategy Pattern.
public interface IClientContextFactory
{
string Context { get; } // Add context to the interface.
}
public class SharePointOnlineClientContext : IClientContextFactory
{
public string Context
{
get
{
return SharePointClientContext.Online.ToString();
}
}
}
// Factory for resolving IClientContext.
public class ClientContextFactory : IClientContextFactory
{
public IEnumerable<IClientContext> _clientContexts;
public Factory(IClientContext[] clientContexts)
{
_clientContexts = clientContexts;
}
public IClientContext GetClientContext(string parameter)
{
IClientContext clientContext = _clientContexts.FirstOrDefault(x => x.Context == parameter);
return clientContext;
}
}
Register them all, just as you did. But instead of injecting IClientContext you inject IClientContextFactor.
There also another solution where you use a Func-factory. Look at option 3, in this answer. One may argue that this is a wrapper for the service locator-pattern, but I'll leave that discussion for another time.
public class ClientContextFactory : IClientContextFactory
{
private readonly Func<string, IClientContext> _createFunc;
public Factory(Func<string, IClientContext> createFunc)
{
_createFunc = createFunc;
}
public IClientContext CreateClientContext(string writesTo)
{
return _createFunc(writesTo);
}
}
And use named registrations:
container.RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString());
container.RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString());
container.RegisterType<IFactory, Factory>(
new ContainerControlledLifetimeManager(), // Or any other lifetimemanager.
new InjectionConstructor(
new Func<string, IClientContext>(
context => container.Resolve<IClientContext>(context));
Usage:
public class MyService
{
public MyService(IClientContextFactory clientContextFactory)
{
_clientContextFactory = clientContextFactory;
}
public void DoStuff();
{
var myContext = SharePointClientContext.Online.ToString();
IClientContextclientContext = _clientContextFactory.CreateClientContext(myContext);
}
}
I have recently started working with Workflows.I am able to pass output of one activity as input to another through making use of OutArgument .Is it possible without using OutArgument.
If Possible please suggest me how?
Thanks all
You can use a workflow extension to act as a repository of variables in the scope of the whole workflow.
Create a workflow extension that contains properties.
Add the extension to the workflow application.
Set or Get the value of the properties from within Activities.
See https://msdn.microsoft.com/en-us/library/ff460215(v=vs.110).aspx
In response to your comment below.
You are wrong in your assumption. The extension "holds" the output from activity 1 which is then available to activity 2.
For example:
Create a class to hold properties:
public class PropertyStoreExtension
{
int _myProperty
public int MyProperty
{
get
{
return this._myProperty;
}
set
{
this._myProperty = value;
}
}
}
Add this as an extension to your workflow:
PropertyStoreExtension propertyStoreExtension = new PropertyStoreExtension
WorkflowInvoker myWorkflowInstence = new
WorkflowInvoker(myWorkflowDefinition());
myWorkflowInstence.Extensions.Add(propertyStoreExtension);
myWorkflowInstence.Invoke()
Your workflow contains 2 activities:
The first takes its "output" and stores it in the extension.
public class Activity1_SetProperty: CodeActivity
{
protected override void Execute(CodeActivityContext context)
{
PropertyStoreExtension pse =context.GetExtension<PropertyStoreExtension>();
if (pse != null)
{
pse.MyProperty=outputValue;
}
}
}
The second gets the value out of the extension.
public class Activity2_GetProperty: CodeActivity
{
protected override void Execute(CodeActivityContext context)
{
PropertyStoreExtension pse =context.GetExtension<PropertyStoreExtension>();
if (pse != null)
{
int intputValue; = pse.MyProperty
}
}
}
After watching the "Enhancements to Code First Migrations: Using HasDefaultSchema and ContextKey for Multiple Model Support" section of Julie Lerman's PluralSite video, "Entity Framework 6: Ninija Edition-What's New in EF 6" (https://app.pluralsight.com/library/courses/entity-framework-6-ninja-edition-whats-new/table-of-contents), it seems there is a way to run multiple schemas under a single database in Entity Framwork 6 using Code First Migrations...
However, based on the video you still need to these package manager commands for each project that houses a separate context:
1. enable-migrations
2. add-migration [MIGRATION NAME]
3. update-database
This is fine and good if you actually care about maintaining migrations going forward, which is not a concern of mine.
What I'd like to do is have each of my Context's initializers set to DropCreateDatabaseAlways, and when I start up my client app (in this case, an MVC site), code first will create the database for the first context used, create the tables in with the correct schema for that context, and then create the tables for the rest of the contexts with the correct schema.
I don't mind if the whole database is dropped and recreated every time I hit F5.
What is happening now is the last context that is accessed in the client app is the only context tables that are created in the database... any contexts being accessed before the last get their tables blown away.
I am currently using two contexts, a Billing context and a Shipping context.
Here is my code:
My client app is an MVC website, and its HomeController's Index method looks like this:
public ActionResult Index()
{
List<Shipping.Customer>
List<Billing.Customer> billingCustomers;
using (var shippingContext = new Shipping.ShippingContext())
{
shippingCustomers = shippingContext.Customers.ToList();
}
using (var billingContext = new Billing.BillingContext())
{
billingCustomers = billingContext.Customers.ToList();
}
}
Here is my DbMigrationsConfigurationClass and ShippingContext class for the Shipping Context:
internal sealed class Configuration : DbMigrationsConfiguration<ShippingContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(ShippingContext context)
{
}
}
public class ShippingContext : DbContext
{
public ShippingContext() : base("MultipleModelDb")
{
}
static ShippingContext()
{
Database.SetInitializer(new ShippingContextInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Shipping");
base.OnModelCreating(modelBuilder);
}
public DbSet<Customer> Customers { get; set; }
class ShippingContextInitializer : DropCreateDatabaseAlways<ShippingContext>
{
}
}
Likewise, here is the DbMigrationConfiguration class for the Billing Context and the BillingContext class:
internal sealed class Configuration : DbMigrationsConfiguration<BillingContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(BillingContext context)
{
}
}
public class BillingContext : DbContext
{
public BillingContext() : base("MultipleModelDb")
{
}
static BillingContext()
{
Database.SetInitializer(new BillingContextInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Billing");
base.OnModelCreating(modelBuilder);
}
public DbSet<Customer> Customers { get; set; }
class BillingContextInitializer : DropCreateDatabaseAlways<BillingContext>
{
}
}
based on the order that the contexts are being called in the controller's action method, whichever context is accessed last is the only context that is created... the other context is wiped out.
I feel like what I'm trying to do is very simple, yet code first migrations, as well as trying to "shoehorn" Entity Framework to represent multiple contexts as separate schemas in the same physical database seems a bit "hacky"...
I'm not that versed with migrations to begin with, so what I'm trying to do might not make any sense at all.
Any feedback would be helpful.
Thanks,
Mike