I'm developing a windows service that reads information from the app.config at start-up which should allow us to change internal thread configuration without redeploying the service.
I created some custom configuration sections and elements as follows (implementation omitted):
public class MyConfigurationSection
{
[ConfigurationProperty("threads")]
[ConfigurationCollection(typeof(MyThreadCollection), AddItemName="addThread")>
public MyThreadCollection threads { get; }
}
public class MyThreadCollection
{
protected override void CreateNewElement();
protected override object GetElementKey(ConfigurationElement element);
}
public class MyThreadElement
{
[ConfigurationProperty("active", DefaultValue=true, IsRequired=false)>
public bool active { get; set; }
[ConfigurationProperty("batchSize", DefaultValue=10, IsRequired=false)>
public int batchSize { get; set; }
[ConfigurationProperty("system", IsRequired=true)>
public string system { get; set; }
[ConfigurationProperty("department", IsRequired=true)>
public string department { get; set; }
[ConfigurationProperty("connection", IsRequired=true)>
public MyThreadConnectionElement connection { get; set; }
}
public class MyThreadConnectionElement
{
[ConfigurationProperty("server", IsRequired=true)>
public string server { get; set; }
[ConfigurationProperty("database", IsRequired=true)>
public string database { get; set; }
[ConfigurationProperty("timeout", DefaultValue=15, IsRequired=false)>
public int timeout { get; set; }
}
Then I add some elements to the app.config as follows:
<configurationSection>
<threads>
<addThread
active="True"
batchSize="50"
system="MySystem1"
department="Department1">
<connectionString
server="MyServer"
database="Database1" />
</addThread>
<addThread
active="True"
batchSize="30"
system="MySystem2"
department="Department2">
<connectionString
server="MyServer"
database="Database2" />
</addThread>
</threads>
</configurationSection>
Everything works - configuration is read, threads are created, and the processes run.
The problem is, I would like both these threads to have the same system name/value -- both should be MySystem -- but when I do that and run the program, I get a The entry 'MySystem' has already been added. exception.
I figured it might be because a property has to be explicitly configured to allow duplicates, but I don't know how and I couldn't find a property of the ConfigurationProperty class that might allow that, other than IsKey, but from its description it didn't seem like the answer, and trying it didn't solve the problem. Am I on the right track here?
Initially the system property was named name and I though that just maybe any property named name is treated as a unique identifier, so I changed it to system but it didn't change anything.
I tried the <clear /> tag as some other, similar posts suggested, without success.
Do I need to add another hierarchy to the configuration section -- Config -> Department -> Thread instead of Config -> Thread? I'd prefer to not take this approach.
Thanks for any and all input.
I actually found the problem and solution quite some time ago, but forgot to post the answer; thanks #tote for reminding me.
When implementing the ConfigurationElementCollection class, the GetElementKey(ConfigurationElement) method can be overridden. Without immediately realising what the method is for I overrode it and simply returned the system property value, and, since more than one configuration element had the same system name, technically they had the same key, which is why the error occurred.
The solution for me was to return the system and the department values as system.department which resulted in unique keys.
Related
I have some models like those below:
public class Mutant
{
public long Id { get; set; }
...
// Relations
public long OriginalCodeId { get; set; }
public virtual OriginalCode OriginalCode { get; set; }
public int DifficultyLevelId { get; set; }
public virtual DifficultyLevel DifficultyLevel { get; set; }
}
and
public class OriginalCode
{
public long Id { get; set; }
...
// Relations
public virtual List<Mutant> Mutants { get; set; }
public virtual List<OriginalCodeInputParameter> OriginalCodeInputParameters { get; set; }
}
and in the OnModelCreating of DBContext I made the relations like these:
modelBuilder.Entity<Mutant>()
.HasOne(m => m.OriginalCode)
.WithMany(oc => oc.Mutants)
.HasForeignKey(m => m.OriginalCodeId)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);
modelBuilder.Entity<Mutant>()
.HasOne(m => m.DifficultyLevel)
.WithMany(dl => dl.Mutants)
.HasForeignKey(m => m.DifficultyLevelId)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);
now when I request for Mutants, the OriginalCode is null:
but as soon as I request for OriginalCodes like below:
then the OriginalCode field of the mutants will be not null:
What is the reason and how could I fix it?
The reason is explained in the Loading Related Data section of the EF Core documentation.
The first behavior is because EF Core currently does not support lazy loading, so normally you'll get null for navigation properties until you specifically load them via eager or explicit loading. However, the Eager loading section contains the following:
Tip
Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.
which explains why the navigation property is not null in the second case.
Now, I'm not sure which of the two behaviors do you want to fix, so will try to address both.
The first behavior can be "fixed" by using one of the currently available methods for loading related data, for instance eager loading:
var mutants = db.Mutants.Include(m => m.OriginalCode).ToList();
The second behavior is "by design" and cannot be controlled. If you want to avoid it, make sure to use fresh new DbContext instance just for executing a single query to retrieve the data needed, or use no tracking query.
Update: Starting with v2.1, EF Core supports Lazy Loading. However it's not enabled by default, so in order to utilize it one should mark all navigation properties virtual, install Microsoft.EntityFrameworkCore.Proxies and enable it via UseLazyLoadingProxies call, or utilize Lazy-loading without proxies - both explained with examples in the EF Core documentation.
Using Package Manager Console install Microsoft.EntityFrameworkCore.Proxies
install-package Microsoft.EntityFrameworkCore.Proxies
And then in your Context class add .UseLazyLoadingProxies():
namespace SomeAPI.EFModels
{
public partial class SomeContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(connectionString);
}
}
}
}
Assume I've read and googled, and I still don't know what I'm doing incorrectly. Whenever I try to execute
_dbContext.Set<T>().Add(aMediaObjectWithAssociatedProvider);
_dbContext.SaveChanges();
I get the dreaded efcore violation of primary key constraint reference table
I have a class as such:
public class Media : BaseModel
{
public virtual string Title { get; set; }
public virtual string? Description { get; set; }
public virtual string Source { get; set; }
public virtual Guid? MediaTypeId { get; set; }
public virtual Guid? ProviderId { get; set; }
public virtual DateTime? StartDate { get; set; }
public virtual DateTime? EndDate { get; set; }
public virtual Provider? Provider { get; set; }
}
The BaseModel class is
public abstract class BaseModel : IBaseModel
{
public virtual Guid Id { get; set; }
}
The Provider class is as such:
public class Provider : BaseModel
{
public virtual string Name { get; set; }
public virtual string? ApiUsername { get; set; }
public virtual string? ConfigurationSection{ get; set; }
}
My DBContext has the following:
protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Media>().HasKey(x => x.Id);
mb.Entity<Media>().HasOne(p => p.Provider).WithOne().HasForeignKey<Media>(x => x.ProviderId);
}
The code for inserting a new object is as follows:
public T Insert(T oneObject)
{
try
{
// Ensure the entity has an ID
if (oneObject.Id == Guid.Empty)
{
oneObject.Id = Guid.NewGuid();
}
_dbContext.Set<T>().Add(oneObject);
_dbContext.SaveChanges();
}
catch (Exception error)
{
_logger.LogError(error.Message, error);
}
return oneObject;
}
Assume that providers are static, in a sense that they already exist in their table, and I don't want to add new providers when I save media... Media just needs to have a provider.
I know exactly what is happening (the model, after travelling through json back through the api to the server is losing context, but I'm also trying to build a repository type of system where I don't have to build complex save logic for every object. (hence why i'm hand wringing over adding code that loads existing providers).
This problem specifically began rearing its head when I was saving new Media objects into the database with existing Providers. I am still mulling over how to look up children dynamically, but i'm not quite there yet.
I've been at this for so long, i'm about ready to give up on efcore relations and just rebuild the models as single objects, and handle all of the manipulation in javascript. And I don't like this idea.
I know for a fact that there will be questions for more code, but please let me know what. Again, I'm just stepping into .net core / ef core so this code-first is a little confusing for me. Thanks
You may have 2 options to try. Do backup your whole project and database beforehand. Clone your database to another database name. Try these either one option using new cloned database for testing.
No.1
Set "newid()" without quotes in your ID's default value in sql server. So you don't need to use Guid.NewGuid() in code every insert. newid() will auto generate GUID.
No. 2
How about removing primary key from ID (GUID) and then creating new column "UID" (running number) and set UID (running number) as primary key and enable its identity? You need to change all other tables too. And re-link UID each other if you use relationship. This way, your UID will not have existing number when insert.
I have two tables:
public AdminTest()
{
this.AdminTestQuestions = new List<AdminTestQuestion>();
}
public int AdminTestId { get; set; }
public string Title { get; set; }
public virtual ICollection<AdminTestQuestion> AdminTestQuestions { get; set; }
}
public partial class AdminTestQuestion
{
public int AdminTestQuestionId { get; set; }
public int AdminTestId { get; set; }
public System.Guid QuestionUId { get; set; }
public virtual AdminTest AdminTest { get; set; }
}
I am using the following EF6 code to add a new adminTest (with its adminTestQuestions) to the
database:
public async Task<IHttpActionResult> Post([FromBody]AdminTest adminTest)
{
db.AdminTests.Add(adminTest);
foreach (AdminTestQuestion adminTestQuestion in adminTest.AdminTestQuestions)
{
db.AdminTestQuestions.Add(adminTestQuestion);
}
await db.SaveChangesAsync(User, DateTime.UtcNow);
return Ok(adminTest);
}
I have similar but more complicated code to deal with the case where questions are added or removed from the adminTest. All my code works but it would be very good if EF was able to do what I needed rather than my having to add many lines of code.
Can anyone tell me if there have been any changes to EF6 or if any changes are planned to EF7 that will allow it
has noted on the ef7 github they seams to have added some neat code that add primary key entity.
but it is still not clear as to if it will be a common thing for children collection in an entity.
Git hub Entity Framework Design Meeting Notes
but for EF6 you could use a Generic Repository to make all the work for you. (since you can't extend DbContext directly)
assuming db is a DbContext
you could use this -> : Accessing a Collection Through Reflection
then find all Property from a class T that contains ICollection<> and do a foreach on the item of the ICollection Property then do db.Set.Add(proprietyChild) on it
that would eliminate the need for always repeating the same add child to entity code.
some people already did implement a solution thou : Automated updates of a graph of deached entities
Look at this complex type, which is basically a DTO that wraps some entities. I don't need to track these entities or use the for updating or any of that stuff, I just want to send them down to the client. The stuff at the top are non-entities just to let me know that I'm not crazy.
public class ResultDetail
{
// non entities (some are even complex) - this works GREAT!
public string WTF { get; set; }
public IEnumerable<int> WTFs { get; set; }
public SomethingElse StoneAge { get; set; }
public IEnumerable<SomethingElse> StoneAgers { get; set; }
// these are entities - none of this works
public EntityA EntityA { get; set; }
public IEnumerable<EntityB> EntityB { get; set; }
}
public class SomethingElse
{
public int ShoeString { get; set; }
}
Now look at this:
http://i.snag.gy/tI9O9.jpg
Not a single entity property shows up on the client side generated types. Are there attributes or something that I can or do I really need to create DTO objects for every one of these entity types? There are more than 2 as in my sample and they have many properties.
By the way these entity types have been generated on the client because of the normal query operations in the domain service that work with them.
This is not possible as current Ria services framework is mainly designed for tracking entities, and for Ria services it is not possible to detect which properties to serialized and which to note, since every entity has navigation properties, serializing properties may cause infinite loops or long loops as there is no control over how to navigate object graph.
Instead you are expected to program your client in such way so that you will load relations on demand correctly.
I have a usercontrol which is responsible for presenting creation and change of users.
The usercontrol is bound to an entity delivered by a RIA Service:
[MetadataType(typeof(User.UserMetadata))]
public partial class User
{
internal class UserMetadata
{
protected UserMetadata() {}
[Required]
public string Name { get; set; }
[Exclude]
public string PasswordHash { get; set; }
[Exclude]
public int PasswordSalt { get; set; }
[Required]
public string ShortName { get; set; }
[Include]
public IEnumerable<UserRole> UserRoles { get; set; }
}
[DataMember]
[RegularExpression("^.*[^a-zA-Z0-9].*$", ErrorMessageResourceName = "BadPasswordStrength", ErrorMessageResourceType = typeof(ErrorResources))]
[StringLength(25, MinimumLength = 6)]
public string NewPassword { get; set; }
}
When creating a new user, the field "NewPassword" is required - but when changing properties of an existing user, it is not (it is used for password-changes).
What is the best approach to solve this? I have several ideas, but they all feels a little bit crappy :-)
Thanks
It appears you are passing your current passwords back to the GUI. There is no need to ever do that. That would create a potential security hole
Suggest you treat password changing as a separate service call, not just a simple record editing exercise. RIA services supports Invoke Operations which are basically arbitrary direct-calls to your RIA service. The only restriction on Invoke operations is that they cannot return complex types (not a problem for this example).
Pass your current logged-in user identifier, the current password (encoded) and the new password (encoded) and do all the work server side. Return a simple success boolean value.
Just some suggestions, I am happy to see other people's ideas on this one :)