FluentValidation: How does the automatic registration know which validator to use? - .net-core

I know that FluentValidation supports automatic validator registration like
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Name).NotNull();
RuleFor(customer => customer.Address).SetValidator(new AddressValidator());
}
}
And in the startup.cs
services.AddValidatorsFromAssemblyContaining<Program>();
But how does the automatic registration know which validator to use when you have multiple entities with corresponding validators like
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Name).NotNull();
RuleFor(customer => customer.Address).SetValidator(new AddressValidator());
}
}
and
public class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(x => x.Id).NotNull();
RuleFor(x => x.Name).Length(0, 10);
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).InclusiveBetween(18, 60);
}
}
How does FlueentValidation know which validator to apply?

Related

.NET efcore 7 JSON COLUMN PROBLEMS

as you know, jsoncolumn support has arrived for efcore7.
I quickly used
yes, I had no problems with creating columns with migration. I added new data
but i have the following problem in query operation
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<IdentitySchema>().OwnsMany(
identitySchema => identitySchema.AuthorityCodes, ownedNavigationBuilder =>
{
var q=ownedNavigationBuilder.ToJson();
})
.OwnsMany(
identitySchema => identitySchema.UserIds, ownedNavigationBuilder =>
{
var x= ownedNavigationBuilder.ToJson();
}); ;
base.OnModelCreating(builder);
}
public class UserAg
{
public string UserId { get; set; }
}
_context.IdentitySchema.Select(f => new
{
f.UserIds,
f.AuthorityCodes
}).Where(f => f.UserIds.Any(f => f.UserId == "1")).ToList();

DevExtreme DataGrid ColorBox

I am trying to make one of the cells in my datagrid display the "ColorBox" so users can choose a colour.
This is my model:
public class Colour : ModelWrapper
{
public string Name { get; set; }
public string BorderColour { get; set; }
public string BackgroundColour { get; set; }
public string HighlightColour { get; set; }
public string HighlightBorder { get; set; }
public string HighlightBackground { get; set; }
}
This is the code for the grid:
#(Html.DevExtreme().DataGrid<Colour>()
.ID("GridView")
.ShowBorders(true)
.DataSource(d => d.Mvc().Controller("Colours").LoadAction("Get").DeleteAction("HardDelete").UpdateAction("Put").InsertAction("Post").Key("Id"))
.Columns(columns =>
{
columns.AddFor(m => m.Active);
columns.AddFor(m => m.Name);
columns.AddFor(m => m.BorderColour);
columns.AddFor(m => m.BackgroundColour);
columns.AddFor(m => m.HighlightColour);
columns.AddFor(m => m.HighlightBorder);
columns.AddFor(m => m.HighlightBackground);})
.Paging(p => p.PageSize(AppConstants.GridControlPageSize))
.FilterRow(f => f.Visible(true))
.HeaderFilter(f => f.Visible(true))
.GroupPanel(p => p.Visible(true))
.Grouping(g => g.AutoExpandAll(false))
.RemoteOperations(true)
.ColumnChooser(c => c.Enabled(true))
.StateStoring(s => s
.Enabled(true)
.Type(StateStoringType.LocalStorage)
.StorageKey(storageName))
.Editing(editing =>
{
editing.Mode(GridEditMode.Form);
editing.AllowAdding(true);
editing.AllowDeleting(true);
editing.AllowUpdating(true);
})
)
For example, here is one of the columns I want to enable users to use the ColorBox for:
columns.AddFor(m => m.BackgroundColour);
It appears that this should be possible looking at some example code here. (Admittedly this code is marked as "2 years old"):
settings.Columns.Add(column =>
{
column.FieldName = "Colour";
column.Caption = "Colour";
column.Width = 100;
column.ColumnType = MVCxGridViewColumnType.ColorEdit;
ColorEditProperties props = (ColorEditProperties)column.PropertiesEdit;
props.ColumnCount = 8;
props.EnableCustomColors = true;
ColorEditItemCollection colours = new ColorEditItemCollection();
colours.CreateDefaultItems(false);
props.Items.Assign(colours);
});
It seems to be linked to the ColumnType property but when I look at the DevExtreme documentation the column object doesn't appear to have this property.
Can anyone shed any light?
I dont have a machine which runs devextreme right now but the following should be correct.
.OnEditorPreparing("your_js_function")
Put this after columns:
.Columns(columns =>
{
columns.AddFor(m => m.Active);
columns.AddFor(m => m.Name);
columns.AddFor(m => m.BorderColour);
columns.AddFor(m => m.BackgroundColour);
columns.AddFor(m => m.HighlightColour);
columns.AddFor(m => m.HighlightBorder);
columns.AddFor(m => m.HighlightBackground);})
.OnEditorPreparing("your_js_function")
Now a bit of explaination. This js function that you bind to the columns will run for each editor. All columns have a different editor which you can overwrite using this js function.
<script type="text/javascript">
function your_js_function(e) {
if (e.dataField == "BackgroundColour") {
e.editorName = "dxColorBox"; // Changes the editor's type
e.editorOptions.onValueChanged = function (args) {
// Implement your logic here
}
}
}
The official devexpress example is here in the customize editors part. As you will see in the link there are other ways to achieve your result as well. I suggest using a debugger so you can see what e contains.
Also a tip when googling for errors devexpress unfortunately runs on many different versions (VB, C#, Jquery) I think the fastest way would be to find what you are looking for from the documentation.

FluentValidation set validator on collection with Ruleset

I'm creating a POST Rest API(ASP.NET Web API) to perform write operations,so have to validate data before inserting them into Database.I'm pretty new to using FluentValidation to validate the data.
Suppose below are classes that I have and need to validate.
public class Listing
{
public Type Type { get; set; }
public Source Source { get; set; }
public List<ListingDetails> ListingDetails { get;set; }
}
public class ListingDetails
{
public int Id{ get; set; }
public ListingStatus Status { get; set; }
}
public enum ListingStatus
{
Active = 1,
Converted = 2,
LostToCompetitor = 3
}
Below code is responsible for validating the status based on the provided ruleset.
public class ListingStatusValidator : AbstractValidator<ListingDetails>
{
public ListingStatusValidator()
{
RuleSet("A", () =>
{
RuleFor(x=>x.InquiryId).GreaterThan(0);
});
RuleSet("B", () =>
{
RuleFor(x => x.Status).IsInEnum().NotEqual(ListingStatus.Active);
});
RuleSet("C", () =>
{
RuleFor(x => x.Status).IsInEnum();
});
}
}
Below is the piece of code used to validatelisting.
public class ListingValidator : AbstractValidator<Listing>
{
public ListingValidator()
{
RuleSet("common", () =>
{
When(x => x.ListingDetails != null && x.ListingDetails.Count <= 1000, () =>
RuleForEach(x => x.ListingDetails).SetValidator(new ListingStatusValidator()));
});
}
}
Now to validate we will call validate method of the validator like below.
var validation = new ListingValidator().Validate(listing,ruleSet:"common");
Is it possible to pass ruleset when validating using setvalidator on collection of objects.Please see below snippet to understand what I'm trying to achieve.
public class ListingValidator : AbstractValidator<Listing>
{
public ListingValidator()
{
When(x => x.ListingDetails != null && x.ListingDetails.Count <= 1000, () =>
RuleForEach(x => x.ListingDetails).SetValidator(new ListingStatusValidator(),ruleset:"A,B,C"));
}
}
You can execute more then one RuleSet using RulesetValidatorSelector
var validation = new ListingValidator()
.Validate(listing, new RulesetValidatorSelector("common", "A", "B", "C"));
In this case you don't need to specify RuleSets for ListingStatusValidator, RuleSets from ListingValidator will be passed to nested validator.

Entity Framework - Code First - TPH and WillCascadeOnDelete(true)

I have an issue when using TPH and WillCascadeOnDelete(true). When I have the value set on true for cascade on delete my database is not created. The exception message is the following one:
Introducing FOREIGN KEY constraint 'FK_dbo.MembersProfiles_dbo.Contacts_ContactId' on table 'MembersProfiles' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
In order to clear things out here is my model and the mapping used for it.
public class MemberProfile
{
public Guid MemberProfileId { get; set; }
public ICollection<Contact> Contacts { get; set; }
}
public abstract class Contact
{
public Guid ContactId { get; set; }
public Guid AddressId { get; set; }
public Address Address { get; set; }
}
public class PersonContact : Contact
{
public string Profession { get; set; }
public string OrganizationName { get; set; }
}
public class OrganizationContact : Contact
{
public string SalesPhone { get; set; }
public string ServicePhone { get; set; }
}
public class ContactMap : EntityTypeConfiguration<Contact>
{
public ContactMap()
{
ToTable("Contacts");
HasKey(c => c.ContactId);
Property(c => c.ContactId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(c => c.Name).IsRequired().HasMaxLength(50);
Property(c => c.Email).IsRequired().HasMaxLength(150);
Property(c => c.MobilePhone).IsRequired().HasMaxLength(15);
Property(c => c.Description).IsOptional().HasMaxLength(500);
Property(c => c.FixPhone).IsOptional().HasMaxLength(15);
Property(c => c.FaxNumber).IsOptional().HasMaxLength(15);
HasRequired(mp => mp.Address).WithMany().HasForeignKey(mp => mp.AddressId);
HasRequired(mp => mp.Link).WithMany().HasForeignKey(mp => mp.LinkId);
HasRequired(mp => mp.Image).WithMany().HasForeignKey(mp => mp.MediaId);
}
}
public class PersonContactMap : EntityTypeConfiguration<PersonContact>
{
public PersonContactMap()
{
Property(pc => pc.Profession).IsOptional().HasMaxLength(150);
Property(pc => pc.OrganizationName).IsOptional().HasMaxLength(150);
Map(pc => pc.Requires("Discriminator").HasValue("PersonContact").HasColumnType("nvarchar(max)")); }
}
public class OrganizationContactMap : EntityTypeConfiguration<OrganizationContact>
{
public OrganizationContactMap()
{
Property(oc => oc.SalesPhone).IsOptional().HasMaxLength(15);
Property(oc => oc.ServicePhone).IsOptional().HasMaxLength(15);
Map(oc => oc.Requires("Discriminator").HasValue("OrganizationContact").HasColumnType("nvarchar(max)"));
}
}
public class MemberProfileMap : EntityTypeConfiguration<MemberProfile>
{
public MemberProfileMap()
{
ToTable("MembersProfiles");
HasKey(mp => mp.MemberProfileId);
Property(mp => mp.MemberProfileId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(mp => mp.Name).IsRequired().HasMaxLength(50);
Property(mp => mp.DateOfBirth).IsRequired();
Property(mp => mp.Email).IsRequired().HasMaxLength(150);
Property(mp => mp.MobilePhone).IsRequired().HasMaxLength(15);
Property(mp => mp.Summary).IsOptional();
HasRequired(mp => mp.Address).WithMany().HasForeignKey(mp => mp.AddressId).WillCascadeOnDelete(true);
Property(mp => mp.AddressId).HasColumnName("AddressId");
HasOptional(mp => mp.Media).WithMany().Map(mp => mp.MapKey(new[] { "MediaId" })).WillCascadeOnDelete(true);
HasOptional(mp => mp.Tags).WithMany().Map(mp => mp.MapKey(new[] { "TagId" })).WillCascadeOnDelete(true);
HasOptional(mp => mp.Contacts).WithMany().Map(mp => mp.MapKey(new[] { "ContactId" })).WillCascadeOnDelete(true);
}
}
Unfortunately I am not able to realize what am I doing wrong... so any clue would be much appreciated.
P.S: I am using EF 5.0 Code First
See if this BlogPost helps., another option i would try to start adding relation one by one to see where it breaks rather than stacking everything at once. And sometimes it helps to just use individual property mappings rather than Fluent API like you have done. Check out different links on that blog i mentioned above.
Ok, found the issue. I have two tables referring addresses table. In my case both Contacts and MemberProfile hold a reference to Addresses table and in both cases the cascade delete was turned on. Once I turned off the cascade delete on one of the relations everything worked just fine.

NHibernate Relations

I am working with NHibernate and I get this code below:
public class User
{
public User()
{
public virtual int Id { get; set; }
public virtual IList<UserConfirmation> UserConfirmation { get; set; }
public virtual string Email;
}
public User()
{
UserConfirmation = new List<UserConfirmation>();
}
}
public class UserConfirmation
{
public virtual int Id { get; set; }
public virtual User { get; set; }
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id);
Map(x => x.Email);
HasMany(x => x.UserConfirmation)
.Inverse()
.Cascade.All();
Table("user");
}
}
public class UserConfirmationMap : ClassMap<UserConfirmation>
{
public UserConfirmationMap()
{
Id(x => x.Id);
References(x => x.User);
Table("user_confirmation");
}
}
But when I try to query over like this:
QueryOver<UserConfirmation>().Where(x => x.User.Email).Take(1).SingleOrDefault()
Than it says I do not have the property User.Email.
How can I solve this problem?
Problem is you are using x => x.User.Email
this should be done with another alias, which would be user
UserConfirmation userConfirmationAlias;
User userAlias;
QueryOver<UserConfirmation>(() => userConfirmationAlias)
.joinAlias(() => userConfirmationAlias.User , () => userAlias)
.Where(() => userAlias.Email).Take(1).SingleOrDefault()
something like above should do the trick
I think you want something like this.
QueryOver<User>().Where(x => x.Email).Take(1).SingleOrDefault()
x should be a user already. If it's not I would use the intellisense to see what type it thinks it is.
Try doing:
IQueryOver<UserConfirmation,User> qo = _Session.QueryOver<UserConfirmation,User>().Where(x => x.User.Email).Take(1).SingleOrDefault();
You could use LINQ instead of QueryOver:
Query<UserConfirmation>().Where(x => x.User.Email).Take(1).SingleOrDefault()
BTW, .Take(1).SingleOrDefault() is probably not needed. If Email is unique, .SingleOrDefault() will be enough. Otherwise, you can use .FirstOrDefault()

Resources