Need to understand the use of Generics in the code below - workflow

public class MyData
{
public string Email { get; set; }
public string Password { get; set; }
public string UserId { get; set; }
}
public class MyWorkflow : IWorkflow
{
public void Build(IWorkflowBuilder<MyData> builder)
{
builder
.StartWith<CreateUser>()
.Input(step => step.Email, data => data.Email)
.Input(step => step.Password, data => data.Password)
.Output(data => data.UserId, step => step.UserId)
.Then<SendConfirmationEmail>()
.WaitFor("confirmation", data => data.UserId)
.Then<UpdateUser>()
.Input(step => step.UserId, data => data.UserId);
}
}
https://github.com/danielgerlag/workflow-core
Trying to understand this piece of code above.
Line 13 has StartWith<CreateUser>() but I don't see anywhere CreateUser type being used at all so whats the use of CreateUser?
and also how do i know what is the object step and data in line 14?

Related

Entity Framework Core Entity > Value Object > Entity Relationship

I have the following classes
public class Slot : Entity
{
public SnackPile SnackPile { get; set; }
public SnackMachine SnackMachine { get; set; }
public int Position { get; }
protected Slot()
{
}
public Slot(SnackMachine snackMachine, int position)
{
SnackMachine = snackMachine;
Position = position;
SnackPile = SnackPile.Empty;
}
}
public class Snack : AggregateRoot
{
public string Name { get; set; }
public Snack()
{
}
private Snack(long id, string name)
{
Id = id;
Name = name;
}
}
public class SnackPile : ValueObject
{
public Snack Snack { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
protected SnackPile()
{
}
public SnackPile(Snack snack, int quantity, decimal price)
{
Snack = snack;
Quantity = quantity;
Price = price;
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Snack;
yield return Quantity;
yield return Price;
}
}
I'm trying to build my relationships using Entity Framework Core but my SnackPiles and Snacks are all null when trying to load them in my UI. However if I only set up my SnackMachines, all my of SnackPiles load fine but have null Snacks.
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<SnackMachine>(entity =>
{
entity.OwnsOne<Money>(e => e.MoneyInside, MoneyInside =>
{
MoneyInside.Property(mi => mi.OneCentCount).HasColumnName("OneCentCount");
MoneyInside.Property(mi => mi.TenCentCount).HasColumnName("TenCentCount");
MoneyInside.Property(mi => mi.QuarterCentCount).HasColumnName("QuarterCentCount");
MoneyInside.Property(mi => mi.OneDollarCount).HasColumnName("OneDollarCount");
MoneyInside.Property(mi => mi.FiveDollarCount).HasColumnName("FiveDollarCount");
MoneyInside.Property(mi => mi.TenDollarCount).HasColumnName("TenDollarCount");
}).Ignore(o => o.MoneyInTransaction);
});
builder.Entity<Slot>(entity =>
{
entity.Property(e => e.Position);
entity.OwnsOne<SnackPile>(e => e.SnackPile, SnackPile =>
{
SnackPile.Property(sp => sp.Quantity).HasColumnName("Quantity");
SnackPile.Property(sp => sp.Price).HasColumnName("Price").HasColumnType("Decimal");
});
});
}
}
I have two questions. Doing this, I get a shadow property called SnackPile_SnackId which I would like named SnackId but nothing I do accomplishes this without creating both properties and the SnackPile_SnackId is set up as the FK.
The next question, is.. is this relationship attainable in Entity Framework Core 3? It appears I have an Entity that has a value object containing the Id of another Entity which I would like to reference.
The result I would like to get can be done with NHibernate
public class SlotMap : ClassMap<Slot>
{
public SlotMap()
{
Id(x => x.Id);
Map(x => x.Position);
Component(x => x.SnackPile, y =>
{
y.Map(x => x.Quantity);
y.Map(x => x.Price);
y.References(x => x.Snack).Not.LazyLoad();
});
References(x => x.SnackMachine);
}
}
Further reference is that I'm following the DDDInPractice course on PluralSite which uses NHibernate (It's an amazing course and highly recommend). Using EF is a learning exercise to see the nuances. The course owner referred me to his blog post on the subject but there have been changes to EF since then. I have an ok understanding for a lot of these concepts but I'm stuck here.
Number 6 in the list:
https://enterprisecraftsmanship.com/posts/ef-core-vs-nhibernate-ddd-perspective/
The problem is that I wasn't using lazy loading.

EF Core: Only part of the model is saved to the database

I try to use EF core, but only a part of my model is saved to the database.
This is my model:
public class EngineType
{
public string Name { get; set; }
}
public class Car
{
public long CarId { get; set; }
public string Name { get; set; }
public EngineType Engine { get; set; }
}
The CarId and the Name is saved, but not the EngineType.
This is the test I use, but actual.Engine is always null:
[TestMethod]
public void WhenIAddAndSaveANewCarThenItIsAddedToDB()
{
using var target = new EFCoreExampleContext();
using var concurrentContext = new EFCoreExampleContext();
var expected = new Car() {CarId = 0815, Name = "Isetta", Engine = new EngineType() { Name = "2Takt" }};
target.Cars.Add(expected);
target.SaveChanges();
var actual = concurrentContext.Cars.Single();
Assert.AreEqual(1, concurrentContext.Cars.Count());
Assert.IsNotNull(actual.Engine);
Assert.AreEqual(expected, actual);
}
My Context looks like this:
public class EFCoreExampleContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseInMemoryDatabase(databaseName: "Add_writes_to_database");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EngineType>(
d =>
{
d.HasKey(e => e.Name);
d.Property(e => e.Name).IsRequired();
});
modelBuilder.Entity<EngineType>(
d =>
{
d.HasKey(e => e.Name);
});
modelBuilder.Entity<Car>(
d =>
{
d.HasKey(e => e.CarId);
d.Property<DateTime>("LastChanged").IsRowVersion().ValueGeneratedOnAddOrUpdate();
d.Property<string>("EngineForeignKey");
d.HasOne(e => e.Engine)
.WithMany()
.HasForeignKey("EngineForeignKey")
.IsRequired();
});
}
}
Any idea what am I doing wrong (or which existing topic answers this question - I even didn't have the right search words to find it).
Thanks!
I think there is no issue with saving. Entity Framework does not do eager loading by default. So you have to explicitly include any navigational properties that should be in result. Try this when you are fetching actual,
using Microsoft.EntityFrameworkCore;
var actual = concurrentContext.Cars.Include(c => c.Engine).Single();

Case insensitive property mapping

When serializing a MongoDB document to a POCO is there any way to make properties map case insensitive? For example I'd like this document:
{
"id": "1"
"foo": "bar"
}
to map to this class:
public MyObj
{
public int Id {get; set;}
public string Foo {get; set;}
}
To do that I think you will have 2 options.
The first would be to write out a class map manually
BsonClassMap.RegisterClassMap<MyClass>(cm => {
cm.AutoMap();
cm.GetMemberMap(c => c.Foo).SetElementName("foo");
});
The second would be to decorate your class with the following attributes
public class MyObj
{
[BsonElement("id")]
public int Id { get; set; }
[BsonElement("foo")]
public string Foo { get; set; }
}
The CSharp driver team have a good tutorial on serialization on the following link
http://docs.mongodb.org/ecosystem/tutorial/serialize-documents-with-the-csharp-driver/
Update
I have just tried the following and this works for me, obviously I'm sure this is a much more simplified version of your code but taking a guess at how it might look.
I have registered the two class maps separately and added the BsonKnownType to the base class.
[BsonKnownTypes(typeof(GeoJSONObject))]
public class Point
{
public string Coordinates { get; set; }
}
public class GeoJSONObject : Point
{
public string Type { get; set; }
}
static void Main(string[] args)
{
var cn = new MongoConnectionStringBuilder("server=localhost;database=MyTestDB;");
var settings = MongoClientSettings.FromConnectionStringBuilder(cn);
var client = new MongoClient(settings);
BsonClassMap.RegisterClassMap<Point>(cm =>
{
cm.AutoMap();
cm.GetMemberMap(c => c.Coordinates).SetElementName("coordinates");
});
BsonClassMap.RegisterClassMap<GeoJSONObject>(cm =>
{
cm.AutoMap();
cm.GetMemberMap(c => c.Type).SetElementName("type");
});
var result = client.GetServer()
.GetDatabase("MyTestDB")
.GetCollection("MyCol")
.Find(Query.EQ("type", BsonValue.Create("xxxx")));
}
I see that it is old question, but people still may search it. At least I found it while was asking the same question.
The CamelCaseElementNameConvention can be used to apply this globally.
var pack = new ConventionPack();
pack.Add(new CamelCaseElementNameConvention());
ConventionRegistry.Register("Camel case convention", pack, t => true);
Documentation: https://mongodb.github.io/mongo-csharp-driver/2.14/reference/bson/mapping/conventions/

How to map a string property to a binary column in the database?

I have a class for a user entity. One of the properties is the user's password (a hash, actually). I made it a string (streamlined code):
public class User
{
public virtual int Id { get; set; }
public virtual string Password { get; set; }
}
There's also a Fluent NHibernate mapping (streamlined code):
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("users");
Id(x => x.Id).GeneratedBy.Sequence("users_id_seq");
Map(x => x.Password); // what do I put here???
}
}
The database column is of bytea data type on PostgreSQL. The above mapping doesn't work, because the property is string (text). What should I do?
you can Make Password a public property, which is only used to reference to the underlying private property HashedPassword.
something like so:
protected virtual byte[] /*or whatever the type is*/ HashedPassword {get; set;}
public virtual string Password
get
{
return (string)(HashedPassword); //or however you want to cast it to string...
}
set
//...
you can then tell fluent nHib to ignore your Password property.
Here is the final solution which works both ways (read & write), what I tried earlier didn't work properly. Hope this will help somebody.
public class User
{
private byte[] _password;
public virtual int Id { get; private set; }
public virtual string Password
{
get { return System.Text.Encoding.Unicode.GetString(_password); }
set { _password = System.Text.Encoding.Unicode.GetBytes(value); }
}
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("users");
Id(x => x.Id).GeneratedBy.Sequence("users_id_seq");
Map(x => x.Password)
.Access.LowerCaseField(Prefix.Underscore)
.CustomType<byte[]>();
}
}

Telerik Grid with Identical Property Names

I'm working on a medical application where a grid needs to display the ICD description as well as its associated HCC category description. The ICD and HCC types look like this:
public class ICD {
public String Code { get; set; }
public String Description { get; set; }
public HCC HCC { get; set; }
}
public class HCC {
public Int32 ID { get; set; }
public String Description { get; set; }
}
When I bind the Telerik MVC extensions grid to a list of ICD objects, I'm setting up the columns like so:
this.Html.Telerik().Grid(this.Model.ICDs)
.Name("ICDGrid")
.DataKeys(keys => keys.Add(icd => icd.Code))
.DataBinding(binding => {
binding.Ajax().Select(this.Model.AjaxSelectMethod);
binding.Ajax().Update(this.Model.AjaxUpdateMethod);
})
.Columns(columns => {
columns.Bound(icd => icd.ICDType.Name).Title("ICD 9/10");
columns.Bound(icd => icd.Code);
columns.Bound(icd => icd.Description);
columns.Bound(icd => icd.HCC.Description).Title("HCC Category")
columns.Command(commands => commands.Delete()).Title("Actions").Width(90);
})
.Editable(editing => editing.Mode(GridEditMode.InCell).DefaultDataItem(new ICD()))
.ToolBar(commands => {
commands.Insert();
commands.SubmitChanges();
})
.Sortable()
.Filterable()
.Pageable(paging => paging.PageSize(12))
.Render();
The problem is that both ICD and HCC have properties named "Description", and I have no control over that. Is there a way to tell Telerik to call them different things in the JavaScript it generates? Something like ICDDescription and HCCDescription?
Currently you cannot alias the properties. What you can do is create a ViewModel object with where the properties are named uniquely. Then bind the grid to the ViewModel object. Here is a code snippet:
public class ICDViewModel
{
public string Description
{
get;
set;
}
public string HCCDescription
{
get;
set;
}
// The rest of the properties of the original ICD class
}
Then you need to change the type of Model.ICDs to use ICDViewModel. You can use the Select extension method to map ICD to ICDViewModel:
Model.ICDs = icds.Select(icd => new ICDViewModel
{
Description = icd.Description,
HCCDescription = icd.HCC.Description
/* set the rest of the ICD properties */
});