I want to find all PropertyChangedEventHandler events in my solution, and then find all listeners added to those events. But I can't seem to get a list of the events.
This is all the code in the solution being analyzed:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RoslynTarget
{
public class Example : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public void DoNothing() { }
}
}
And this is my code for analyzing it. references.Count == 1 and r.Locations.Count == 0, but exactly one location should be found. What's going on here?
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.MSBuild;
namespace RoslynTest
{
class Program
{
static void Main(string[] args)
{
const string solutionPath = #"C:\Users\<user>\Code\RoslynTarget\RoslynTarget.sln";
const string projectName = "RoslynTarget";
var msWorkspace = MSBuildWorkspace.Create(new Dictionary<string, string> { { "CheckForSystemRuntimeDependency", "true" } });
var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;
var project =
solution.Projects
.Where(proj => proj.Name == projectName)
.First();
var compilation = project.GetCompilationAsync().Result;
var eventType = compilation.ResolveType("System.ComponentModel.PropertyChangedEventHandler").First();
var references = SymbolFinder.FindReferencesAsync(eventType, solution).Result;
foreach (var r in references)
{
foreach (var loc in r.Locations)
{
// ...
}
}
}
}
}
Extensions.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
namespace RoslynTest
{
public static class Extensions
{
public static IEnumerable<INamedTypeSymbol> ResolveType(this Compilation compilation, string classFullName)
{
return new IAssemblySymbol[] { compilation.Assembly }
.Concat(compilation.References
.Select(compilation.GetAssemblyOrModuleSymbol)
.OfType<IAssemblySymbol>())
.Select(asm => asm.GetTypeByMetadataName(classFullName))
.Where(cls => cls != null);
}
}
}
Recently I've done similar thing where I was trying to find the reference of a method in complete solution.
To use FindReferenceAsync you have create symantic model first and find the symbol from there. Once you have the symbol you can use the FindReferenceAsync.
Here's the snippet that I used and it's working:
var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;
foreach (var project in solution.Projects)
{
foreach (var document in project.Documents)
{
var model = document.GetSemanticModelAsync().Result;
var methodInvocation = document.GetSyntaxRootAsync().Result;
InvocationExpressionSyntax node = null;
try
{
node = methodInvocation.DescendantNodes().OfType<InvocationExpressionSyntax>()
.Where(x => ((MemberAccessExpressionSyntax)x.Expression).Name.ToString() == methodName).FirstOrDefault();
if (node == null)
continue;
}
catch(Exception exception)
{
// Swallow the exception of type cast.
// Could be avoided by a better filtering on above linq.
continue;
}
methodSymbol = model.GetSymbolInfo(node).Symbol;
found = true;
break;
}
if (found) break;
}
foreach (var item in SymbolFinder.FindReferencesAsync(methodSymbol, solution).Result)
{
foreach (var location in item.Locations)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Project Assembly -> {0}", location.Document.Project.AssemblyName);
Console.ResetColor();
}
}
Here's the complete working code. If you want to visualize the Roslyn tree then you can try using Roslyn tree visualizer to see code structuring.
Update
As per discussion in comments with OP Installing Roslyn SDK fixed the issue. Assuming that there might be some updates in SDK to generate Symbols information as compared to Nuget dlls when using GetCompilationAsync.
Related
I already create new custom field for screen Fixed Asset. The following code is my DAC extension:
using PX.Data;
using PX.Objects.CR;
using PX.Objects.CS;
using PX.Objects.EP;
using PX.Objects.FA;
using PX.Objects.GL;
using PX.Objects;
using System.Collections.Generic;
using System;
namespace SGLCustomizeProject
{
public class FALocationHistoryExtension : PXCacheExtension<PX.Objects.FA.FALocationHistory>
{
#region UsrKodeArea
[PXDBString(50)]
[PXUIField(DisplayName = "Kode Area")]
[PXSelector(typeof(Search<KodeAreaMaster.roomCD,
Where<KodeAreaMaster.status,
Equal<statusActive>,
And<KodeAreaMaster.buildingID,
Equal<Current<FALocationHistory.buildingID>>>>>),
typeof(KodeAreaMaster.roomCD),
typeof(KodeAreaMaster.roomDescription),
typeof(KodeAreaMaster.buildingID),
typeof(KodeAreaMaster.status))]
public virtual string UsrKodeArea { get; set; }
public abstract class usrKodeArea : IBqlField { }
#endregion
#region UsrDeskripsiArea
[PXDBString(75)]
[PXUIField(DisplayName = "Deskripsi Area")]
public virtual string UsrDeskripsiArea { get; set; }
public abstract class usrDeskripsiArea : IBqlField { }
#endregion
}
}
I need to fill the selected value into another additional field in the current screen, please see the following screenshot:
I need to fill value of Deskripsi Area from selector field (pop up) into Deskripsi Area field.
I have tried the following code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PX.Common;
using PX.Data;
using PX.Objects.CS;
using PX.Objects.CR;
using PX.Objects.CM;
using PX.Objects.GL;
using PX.Objects.AP;
using PX.Objects.EP;
using PX.Objects.IN;
using PX.Objects.FA.Overrides.AssetProcess;
using PX.Objects;
using PX.Objects.FA;
namespace SGLCustomizeProject
{
public class AssetMaint_Extension : PXGraphExtension<AssetMaint>
{
public virtual void _(Events.FieldUpdated<FALocationHistory, FALocationHistoryExtension.usrKodeArea> e)
{
var row = e.Row;
var ext = row.GetExtension<FALocationHistoryExtension>();
e.Cache.SetValue<FALocationHistoryExtension.usrDeskripsiArea>(row, ext.UsrKodeArea);
}
}
}
This code above has been worked, but the result is when I choose Kode Area field, it also fill into Deskripsi Area field. My goal is to fill Deskripsi Area with the same field (Deskripsi Area) from selector field.
I tried to change code above with the following code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PX.Common;
using PX.Data;
using PX.Objects.CS;
using PX.Objects.CR;
using PX.Objects.CM;
using PX.Objects.GL;
using PX.Objects.AP;
using PX.Objects.EP;
using PX.Objects.IN;
using PX.Objects.FA.Overrides.AssetProcess;
using PX.Objects;
using PX.Objects.FA;
namespace SGLCustomizeProject
{
public class AssetMaint_Extension : PXGraphExtension<AssetMaint>
{
public virtual void _(Events.FieldUpdated<FALocationHistory, FALocationHistoryExtension.usrKodeArea> e)
{
var row = e.Row;
var ext = row.GetExtension<FALocationHistoryExtension>();
e.Cache.SetValue<FALocationHistoryExtension.usrDeskripsiArea>(row, ext.UsrDeskripsiArea);
}
}
}
But it doesn't work. Any step that I forget ?
Change the ALocationHistoryExtension_UsrKodeArea_FieldUpdated to ALocationHistory_UsrKodeArea_FieldUpdated
protected virtual void FALocationHistory_UsrKodeArea_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
if (e.Row is FALocationHistory)
{
sender.SetDefaultExt<FALocationHistoryExtension.usrDeskripsiArea>(e.Row);
}
}
To Override an Event Handler
use xxx_fieldUpdated event
In your aspx page check, that you have commitchanges set to true
[ as usually optional ] sometime is necessary to set autorefresh = true
Starting from 2017 R2 you can also use this approach:
public virtual void _(Events.FieldUpdated<FALocationHistory, FALocationHistoryExtension.usrKodeArea> e)
{
var row = e.Row;
var ext = row.GetExtension<FALocationHistoryExtension>();
e.Cache.SetValue<FALocationHistoryExtension.usrDeskripsiArea>(row, ext.UsrKodeArea);
var KodeAreaMaster =
PXSelect<KodeAreaMaster, Where<KodeAreaMaster.roomCD, Equal<Required<KodeAreaMaster.roomCD>>>>
.Select(Base, ext.UsrKodeArea).First().GetItem<KodeAreaMaster>();
e.Cache.SetValueExt<FALocationHistoryExtension.usrDeskripsiArea>();
}
I used the following code to provide my goal. Thanks for everyone for all the respons. :)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PX.Common;
using PX.Data;
using PX.Objects.CS;
using PX.Objects.CR;
using PX.Objects.CM;
using PX.Objects.GL;
using PX.Objects.AP;
using PX.Objects.EP;
using PX.Objects.IN;
using PX.Objects.FA.Overrides.AssetProcess;
using PX.Objects;
using PX.Objects.FA;
namespace SGLCustomizeProject
{
public class AssetMaint_Extension : PXGraphExtension<AssetMaint>
{
public virtual void _(Events.FieldUpdated<FALocationHistory, FALocationHistoryExtension.usrKodeArea> e)
{
var row = e.Row;
var ext = row.GetExtension<FALocationHistoryExtension>();
if (ext.UsrKodeArea != null)
{
e.Cache.SetValue<FALocationHistoryExtension.usrDeskripsiArea>(row, ext.UsrKodeArea);
var kodeAreaMaster = PXSelect<KodeAreaMaster,
Where<KodeAreaMaster.roomCD,
Equal<Required<KodeAreaMaster.roomCD>>>>
.Select(Base, ext.UsrKodeArea).First().GetItem<KodeAreaMaster>();
e.Cache.SetValueExt<FALocationHistoryExtension.usrDeskripsiArea>(row, kodeAreaMaster.RoomDescription);
}
}
public virtual void _(Events.FieldUpdated<FALocationHistory.buildingID> e)
{
var row = e.Row as FALocationHistory;
var ext = row.GetExtension<FALocationHistoryExtension>();
if (row.BuildingID != null)
{
if (ext.UsrKodeArea != null)
{
var kodeAreaMaster = PXSelect<KodeAreaMaster,
Where<KodeAreaMaster.roomCD,
Equal<Required<KodeAreaMaster.roomCD>>>>
.Select(Base, ext.UsrKodeArea).First().GetItem<KodeAreaMaster>();
if (row.BuildingID == kodeAreaMaster.BuildingID)
{
return;
}
else
{
e.Cache.SetValueExt<FALocationHistoryExtension.usrKodeArea>(row, null);
e.Cache.SetValueExt<FALocationHistoryExtension.usrDeskripsiArea>(row, null);
}
}
}
else
{
e.Cache.SetValueExt<FALocationHistoryExtension.usrKodeArea>(row, null);
e.Cache.SetValueExt<FALocationHistoryExtension.usrDeskripsiArea>(row, null);
}
}
}
}
I want to get a reference to the current solution, using the DTE object with C# in Visual Studio 2015.
using System;
using EnvDTE;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
namespace TemplatesExample
{
class Program
{
static void Main(string[] args)
{
IVsSolution solution = Package.GetGlobalService(typeof(DTE)) as IVsSolution;
Console.WriteLine(solution.ToString());
Console.ReadKey();
}
}
}
But when I use this, my solution object is always NULL.
So how do I get to my current solution object in VS2015 using C# on .net framework 4.6?
Try this sample. Up and running on VS2015.
( This method is valid only for the same solution ).
using EnvDTE;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace Test
{
public partial class Form1 : Form
{
public class DTEHandle
{
//EnvDTE.Project proj;
//EnvDTE.Configuration config;
//EnvDTE.Properties configProps;
//EnvDTE.Property prop;
EnvDTE.DTE DTE = Marshal.GetActiveObject("VisualStudio.DTE.14.0") as EnvDTE.DTE;
public EnvDTE.Project GetProject(String Name)
{
foreach (EnvDTE.Project item in DTE.Solution.Projects)
{
if (item.Name == Name)
{
return item;
}
}
return null;
}
}
public Form1()
{
InitializeComponent();
EnvDTE.DTE DTE = Marshal.GetActiveObject("VisualStudio.DTE.14.0") as EnvDTE.DTE;
DTEHandle h = new DTEHandle();
EnvDTE.Project proj = h.GetProject("Test");
foreach (EnvDTE.ProjectItem item in proj.ProjectItems)
{
if (item.Name == "Program.cs")
{
TextSelection s = item.Document.Selection as TextSelection;
s.SelectAll();
MessageBox.Show(s.Text);
}
}
}
}
}
I have a promblem with run-time compiled classes. I have something like this 2 classes:
first class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Program.Bullet {
public class Class1{
private int i;
public Class1(int j){
i=j;
}
}
}
and second class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Program.Bullet;
namespace Program.Object {
public class Class2{
public Class2(){
Class1 c1 = new Class1(5);
}
}
}
This two classes I would like to compile in run-time and use them in my project. So I have function to compile it (XmlNode has data about fullPath etc):
private ModuleBuilder moduleBuilder;
private List<string> isCompiled;
private void Compile(XmlNode compileingClasses) {
foreach (XmlNode compileingClass in compileingClasses) {
string fullPath = compileingClass.Attributes["path"].InnerText;
string type = compileingClass.Attributes["name"].InnerText; ;
if (!isCompiled.Contains(type)) {
isCompiled.Add(type);
var syntaxTree = SyntaxTree.ParseFile("../../File1/File2/" + fullPath);
var comp = Compilation.Create("Test.dll"
, syntaxTrees: new[] { syntaxTree }
, references: metadataRef
, options: comilationOption
);
// Runtime compilation and check errors
var result = comp.Emit(moduleBuilder);
if (!result.Success) {
foreach (var d in result.Diagnostics) {
Console.WriteLine(d);
}
throw new XmlLoadException("Class not found " + fullPath);
}
}
}
}
Is it possible to get the reference on Class1 to Class2?
Edit: Better question
Is it possible to create MetadataReference on compiled Class1?
Something like:
string fullName = bullet.Attributes["fullName"].InnerText;
var o = moduleBuilder.GetType(fullName);
metadataRef.Add(new MetadataFileReference(o.Assembly.Location));
This throw NotSupportedException
You're trying to reference the assembly which is currently being built and I don't think Roslyn can do that.
What you can do instead is to create a single Compilation from all your classes (probably having a separate SyntaxTree for each class). If you do that, you won't need any references.
I'm trying to create a simple service using the code provided but i don't understand why have an exception when binding.
10-19 11:42:09.148 I/mono-stdout( 1622): MvxBind:Error: 10.40 Exception thrown during the view binding
MvxBindingLayoutInflatorFactory Line 133!
I need some help please :)
My Source:
DataStore Interface:
using Core.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
namespace Core.Interfaces
{
public interface IDataStore
{
void UpdateFeed(FeedModel feedModel);
void DeleteFeed(FeedModel feedModel);
void CreateFeed(FeedModel feedModel);
FeedModel GetFeed(Uri uri);
ObservableCollection<FeedModel> Feeds { get; }
}
}
DataStore Class:
using System;
using System.Collections.Generic;
using System.Linq;
using Core.Interfaces;
using System.Collections.ObjectModel;
using Cirrious.MvvmCross.Interfaces.ServiceProvider;
using Cirrious.MvvmCross.Interfaces.Platform;
using Cirrious.MvvmCross.Interfaces.Localization;
using Cirrious.MvvmCross.ExtensionMethods;
using Core.Helpers;
using System.Xml.Serialization;
using System.Xml.Linq;
using System.IO;
namespace Core.Models
{
public class DataStore
: IDataStore
, IMvxServiceConsumer<IMvxSimpleFileStoreService>
, IMvxServiceConsumer<IMvxResourceLoader>
{
public DataStore()
{
Load();
}
public void UpdateFeed(FeedModel feedModel)
{
var toUpdate = this.m_feeds.First(feed => feed.Url == feedModel.Url);
toUpdate.CloneFrom(feedModel);
Save();
}
public void DeleteFeed(FeedModel feedModel)
{
this.m_feeds.Remove(this.m_feeds.First(feed => feed.Url == feedModel.Url));
Save();
}
public void CreateFeed(FeedModel feedModel)
{
this.m_feeds.Add(feedModel);
Save();
}
public FeedModel GetFeed(Uri uri)
{
return this.m_feeds.First(feed => feed.Url == uri);
}
private void Load()
{
var fileService = this.GetService<IMvxSimpleFileStoreService>();
if (!fileService.TryReadBinaryFile(LocationDataService.StoreFileName, LoadFrom))
{
var resourceLoader = this.GetService<IMvxResourceLoader>();
resourceLoader.GetResourceStream(LocationDataService.ResourceFileName, (inputStream) => LoadFrom(inputStream));
}
}
private bool LoadFrom(Stream inputStream)
{
try
{
var loadedData = XDocument.Load(inputStream);
if (loadedData.Root == null)
return false;
using (var reader = loadedData.Root.CreateReader())
{
var list = (List<FeedModel>)new XmlSerializer(typeof(List<FeedModel>)).Deserialize(reader);
this.m_feeds = new ObservableCollection<FeedModel>(list);
return true;
}
}
catch
{
return false;
}
}
private void Save()
{
var fileService = this.GetService<IMvxSimpleFileStoreService>();
fileService.WriteFile(LocationDataService.StoreFileName, (stream) =>
{
var serializer = new XmlSerializer(typeof(List<FeedModel>));
serializer.Serialize(stream, m_feeds.ToList());
});
}
private ObservableCollection<FeedModel> m_feeds;
public ObservableCollection<FeedModel> Feeds
{
get { return this.m_feeds; }
}
}
}
BaseViewModel:
using Cirrious.MvvmCross.Commands;
using Cirrious.MvvmCross.ExtensionMethods;
using Cirrious.MvvmCross.Interfaces.Commands;
using Cirrious.MvvmCross.Interfaces.ServiceProvider;
using Cirrious.MvvmCross.ViewModels;
using Core.Interfaces;
namespace Core.ViewModels
{
public class BaseViewModel
: MvxViewModel
, IMvxServiceConsumer<IDataStore>
{
protected IDataStore DataStore
{
get { return this.GetService<IDataStore>(); }
}
}
}
FeedManagerViewModel:
using Cirrious.MvvmCross.Commands;
using Cirrious.MvvmCross.Interfaces.Commands;
using Core.Controls;
using Core.Models;
using System;
using System.Collections.ObjectModel;
namespace Core.ViewModels
{
public class FeedsManagerViewModel
: BaseViewModel
{
public ObservableCollection<FeedModel> Feeds { get { return this.DataStore.Feeds; } }
...
}
}
View xml:
<Mvx.MvxBindableListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
local:MvxBind="{'ItemsSource':{'Path':'Feeds'}, 'ItemClick':{'Path':'DisplayItemCommand'}}"
local:MvxItemTemplate="#layout/feedlist_viewmodel" />
This is most likely an error in your XML... but it's hard to tell from just that one line of trace.
What version of MvvmCross are you running?
The tip version of both Master and vNext show line 133 as
MvxBindingTrace.Trace(MvxTraceLevel.Error, "Exception during creation of {0} from type {1} - exception {2}", name, viewType.FullName, exception.ToLongString());
So hopefully if you use the tip, then that should give you a lot more information about what is going wrong.
Beyond that, you can always try setting a breakpoint on the offending line to extract more information.
If the exception is on line 99 then change the error logging there from:
MvxBindingTrace.Trace(MvxTraceLevel.Error, "Exception thrown during the view binding ", exception.ToLongString());
to:
MvxBindingTrace.Trace(MvxTraceLevel.Error, "Exception thrown during the view binding {0}", exception.ToLongString());
The error will be in there somewhere :)
Another good debugging technique is to comment out lines one-by-one until the problem goes away - this helps identify where the problem is.
You've got a working development environment and a really powerful debugger - using it is a good skill to learn. 'Code Complete' is one of my favourite books ever :)
I want to do exactly what this question asks:
Cascade Saves with Fluent NHibernate AutoMapping
Using Fluent Nhibernate Mappings to turn on "cascade" globally once for all classes and relation types using one call rather than setting it for each mapping individually.
The answer to the earlier question looks great, but I'm afraid that the Fluent Nhibernate API altered its .WithConvention syntax last year and broke the answer... either that or I'm missing something.
I keep getting a bunch of name space not found errors relating to the IOneToOnePart, IManyToOnePart and all their variations:
"The type or namespace name 'IOneToOnePart' could not be found (are you missing a using directive or an assembly reference?)"
I've tried the official example dll's, the RTM dll's and the latest build and none of them seem to make VS 2008 see the required namespace.
The second problem is that I want to use the class with my AutoPersistenceModel
but I'm not sure where to this line:
.ConventionDiscovery.AddFromAssemblyOf()
in my factory creation method.
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.UsingFile(DbFile))
.Mappings(m => m.AutoMappings
.Add(AutoMap.AssemblyOf<Shelf>(type => type.Namespace.EndsWith("Entities"))
.Override<Shelf>(map =>
{
map.HasManyToMany(x => x.Products).Cascade.All();
})
)
)//emd mappings
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();//finalizes the whole thing to send back.
}
Below is the class and using statements I'm trying
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using FluentNHibernate.Conventions;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using FluentNHibernate.Mapping;
namespace TestCode
{
public class CascadeAll : IHasOneConvention, IHasManyConvention, IReferenceConvention
{
public bool Accept(IOneToOnePart target)
{
return true;
}
public void Apply(IOneToOnePart target)
{
target.Cascade.All();
}
public bool Accept(IOneToManyPart target)
{
return true;
}
public void Apply(IOneToManyPart target)
{
target.Cascade.All();
}
public bool Accept(IManyToOnePart target)
{
return true;
}
public void Apply(IManyToOnePart target)
{
target.Cascade.All();
}
}
}
The easiest way I've found to do this for a whole project is to use DefaultCascade:
.Conventions.Add( DefaultCascade.All() );
Go to "The Simplest Conventions" section on the wiki, for this, and a list of others.
Edit:
Here's the list from the Wiki:
Table.Is(x => x.EntityType.Name + "Table")
PrimaryKey.Name.Is(x => "ID")
AutoImport.Never()
DefaultAccess.Field()
DefaultCascade.All()
DefaultLazy.Always()
DynamicInsert.AlwaysTrue()
DynamicUpdate.AlwaysTrue()
OptimisticLock.Is(x => x.Dirty())
Cache.Is(x => x.AsReadOnly())
ForeignKey.EndsWith("ID")
A word of warning - some of the method names in the Wiki may be wrong. I edited the Wiki with what I could verify (i.e. DefaultCascade and DefaultLazy), but can't vouch for the rest. But you should be able to figure out the proper names with Intellisense if the need arises.
Here's a full working example similar to the Getting Started guide https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started
//=====CONSOLE MAIN
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using System.IO;
using FluentNHibernate.Automapping;
using App4.Entities;
using System.Diagnostics;
namespace App4
{
class Program
{
static void Main(string[] args)
{
// create our NHibernate session factory
var sessionFactory = CreateSessionFactory();
using (var session = sessionFactory.OpenSession())
{
// populate the database
using (var transaction = session.BeginTransaction())
{
// create a couple of Stores each with some Products and Employees
var topShelf = new Shelf();
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < 1000; i++)
{
var potatoes = new Product { Name = "Potatoes" + i.ToString(), Price = 3.60 + i };
var meat = new Product { Name = "Meat" + i.ToString(), Price = 4.49 + i };
//session.SaveOrUpdate(potatoes); //===<<cascading save handles this :-)
//session.SaveOrUpdate(meat);
topShelf.Products.Add(meat);
topShelf.Products.Add(potatoes);
}
sw.Stop();
session.SaveOrUpdate(topShelf);
//session.SaveOrUpdate(superMart);
transaction.Commit();
Console.WriteLine("Add Items: " + sw.ElapsedMilliseconds);
}
}
using (var session = sessionFactory.OpenSession())
{
// retreive all stores and display them
using (session.BeginTransaction())
{
var shelves = session.CreateCriteria(typeof(Shelf)).List<Shelf>();
foreach (var store in shelves)
{
WriteShelfPretty(store);
}
}
}
Console.ReadLine();
}
private const string DbFile = "FIVEProgram.db";
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.UsingFile(DbFile))
.Mappings(m => m.AutoMappings
.Add(AutoMap.AssemblyOf<Shelf>(type => type.Namespace.EndsWith("Entities"))
.Override<Shelf>(map =>
{
map.HasManyToMany(x => x.Products);//.Cascade.All();
})
.Conventions.AddFromAssemblyOf<CascadeAll>()
)
) //emd mappings
.ExposeConfiguration(BuildSchema)//Delete and remake db (see function below)
.BuildSessionFactory();//finalizes the whole thing to send back.
}
private static void BuildSchema(Configuration config)
{
// delete the existing db on each run
if (File.Exists(DbFile))
File.Delete(DbFile);
// this NHibernate tool takes a configuration (with mapping info in)
// and exports a database schema from it
new SchemaExport(config)
.Create(false, true);
}
private static void WriteShelfPretty(Shelf shelf)
{
Console.WriteLine(shelf.Id);
Console.WriteLine(" Products:");
foreach (var product in shelf.Products)
{
Console.WriteLine(" " + product.Name);
}
Console.WriteLine();
}
}
}
//Data Classes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace App4.Entities
{
public class Product
{
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
public virtual double Price { get; set; }
}
public class Shelf
{
public virtual int Id { get; private set; }
public virtual IList<Product> Products { get; private set; }
public Shelf()
{
Products = new List<Product>();
}
}
}
//Cascade All Helper Class
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.AcceptanceCriteria;
using FluentNHibernate.Conventions.Inspections;
using FluentNHibernate.Conventions.Instances;
using System;
using System.Collections.Generic;
namespace App4
{
public class CascadeAll :
IHasOneConvention, //Actually Apply the convention
IHasManyConvention,
IReferenceConvention,
IHasManyToManyConvention,
IHasOneConventionAcceptance, //Test to see if we should use the convention
IHasManyConventionAcceptance, //I think we could skip these since it will always be true
IReferenceConventionAcceptance, //adding them for reference later
IHasManyToManyConventionAcceptance
{
//One to One
public void Accept(IAcceptanceCriteria<IOneToOneInspector> criteria)
{
//criteria.Expect(x => (true));
}
public void Apply(IOneToOneInstance instance)
{
instance.Cascade.All();
}
//One to Many
public void Accept(IAcceptanceCriteria<IOneToManyCollectionInspector> criteria)
{
//criteria.Expect(x => (true));
}
public void Apply(IOneToManyCollectionInstance instance)
{
instance.Cascade.All();
}
//Many to One
public void Accept(IAcceptanceCriteria<IManyToOneInspector> criteria)
{
// criteria.Expect(x => (true));
}
public void Apply(IManyToOneInstance instance)
{
instance.Cascade.All();
}
//Many to Many
public void Accept(IAcceptanceCriteria<IManyToManyCollectionInspector> criteria)
{
// criteria.Expect(x => (true));
}
public void Apply(IManyToManyCollectionInstance instance)
{
instance.Cascade.All();
}
}
}
The signature for the conventions has changed. Are you not using something like ReSharper? That would point you to that conclusion.
You can read more about the new conventions on the wiki.