我有一个对象
Nov 10, 2016 4:46:33 PM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.alfresco.repo.webdav.WebDAVSessionListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.eisenvault.autoMailgenerate.createUserHandler' defined in class path resource [alfresco/module/demoact1-repo/context/service-context.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.eisenvault.autoMailgenerate.CreateUserHandler]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1038)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:984)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:633)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.alfresco.web.app.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:63)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.eisenvault.autoMailgenerate.CreateUserHandler]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:163)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1031)
... 23 more
Caused by: java.lang.NullPointerException
at com.eisenvault.autoMailgenerate.CreateUserHandler.<init>(CreateUserHandler.java:30)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
... 25 more
我想向我的API发送一个REST PATCH请求,只更新其中一个属性
{
"_id": "testobject",
"A": "First line",
"B": "Second line",
"C": "Third line"
}
将其解析为类
{
"_id": "testobject",
"C": "Forth line"
}
我现在需要更新MongoDB中的现有文档,但只更新属性public class SomeObject {
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
。
我可以为这一条记录创建一个更新定义
C
或者我可以对每个属性进行硬编码以查看它是否为空
UpdateDefinition<SomeObject> update = Builders<SomeObject>.Update.Set(x => x.C, <value of property C>)
但是,如果我有很多属性和许多子属性,这可能会非常快。另一个问题是,如果我将属性的值设置为故意为空,那么它根本不会更新记录,因为它会查找非空的字段。
如何动态地对.NET中的MongoDB文档进行部分更新,以便我有一个通用的PATCH API调用,可以接受文档所具有的任何参数,只更新指定的属性?
答案 0 :(得分:5)
我建议您避免依赖1.x遗留API,因为它在2.x中也得到了完美支持,如下面的示例代码所示。
var client = new MongoClient();
var database = client.GetDatabase("test");
var collection = database.GetCollection<BsonDocument>("test");
var changesJson = "{ a : 1, b : 2 }";
var changesDocument = BsonDocument.Parse(changesJson);
var filter = Builders<BsonDocument>.Filter.Eq("_id", 1);
UpdateDefinition<BsonDocument> update = null;
foreach (var change in changesDocument)
{
if (update == null)
{
var builder = Builders<BsonDocument>.Update;
update = builder.Set(change.Name, change.Value);
}
else
{
update = update.Set(change.Name, change.Value);
}
}
//following 3 lines are for debugging purposes only
//var registry = BsonSerializer.SerializerRegistry;
//var serializer = registry.GetSerializer<BsonDocument>();
//var rendered = update.Render(serializer, registry).ToJson();
//you can also use the simpler form below if you're OK with bypassing the UpdateDefinitionBuilder (and trust the JSON string to be fully correct)
update = new BsonDocumentUpdateDefinition<BsonDocument>(new BsonDocument("$set", changesDocument));
var result = collection.UpdateOne(filter, update);
致信Robert Stam提供代码示例。
答案 1 :(得分:1)
您可以使用
IMongoUpdate updateDoc = new UpdateDocument("$set", doc);
collection.Update(Query.EQ("_id",id), updateDoc);
但是,你应该小心。
如果您首先将文档反序列化为SomeObject,则所有字段都将获得其默认值(字符串为null,int为0等)。如果您使用该对象进行更新,则json字符串中不存在的字段将更新为其默认值。
如果您使用
var bsonDoc = BsonSerializer.Deserialize<BsonDocument>(jsonString);
IMongoUpdate updateDoc = new UpdateDocument("$set", bsonDoc);
collection.Update(Query.EQ("_id",id), updateDoc);
数据库中的文档将仅针对jsonString中存在的字段进行更新
答案 2 :(得分:0)
不确定谁在这里> = 20年6月,但是我做了以下事情。我正在使用NewtonSoft JObject / JArray,我想创建一个mongo更新解析器/函数,该解析器/函数将不知道传入的架构,也将构建嵌套的文档。我必须习惯的另一件事(我是Mongo的新手)是Bson Update文档中键的语法,即
{ "key.full.path.into.nested.document" : "valueToSet" }
因此,在尝试了几种方法来手动/递归说明传入JSON文档的嵌套/包含路径后,我终于找到了,并且可以为此完美地使用JToken.Path属性。
无论如何,希望这是有人会发现有用的东西。这只是一个示例,对文档结构进行了一些假设,但以当前形式非常有用。而且,像我一样,我认为这可能会帮助一些正在学习Mongo及其C#驱动程序的人,同时还使用JSON.Net封装传入的REST请求。
public BsonDocument ParseUpdateRequest(JObject req)
{
BsonDocument bson = new BsonDocument();
Parse(req, ref bson);
BsonDocument parsedBson = new BsonDocument();
parsedBson["$set"] = bson;
return parsedBson;
}
private void Parse(JObject req, ref BsonDocument bson)
{
/**
* Could use a parent key/node in each recursion call or just use the JToken path
* string.IsNullOrEmpty(parentNode) ? field.Key : parentNode + "." + field.Key;
**/
string key;
JToken val;
foreach (var field in req)
{
key = field.Value.Path;
val = field.Value;
switch (val.Type)
{
case JTokenType.String:
bson.Add(key, (string)val);
break;
case JTokenType.Integer:
bson.Add(key, (int)val);
break;
case JTokenType.Float:
bson.Add(key, (float)val);
break;
case JTokenType.Date:
DateTime dt = (DateTime)val;
bson.Add(key, dt.ToUniversalTime());
break;
case JTokenType.Array:
BsonArray bsonArray = ParseArray((JArray)val);
bson.Add(key, bsonArray);
break;
case JTokenType.Object:
Parse((JObject)val, ref bson);
break;
}
}
return;
}
private BsonArray ParseArray(JArray source)
{
BsonArray bson = new BsonArray();
foreach (JToken field in source)
{
switch (field.Type)
{
case JTokenType.String:
bson.Add((string)field);
break;
case JTokenType.Date:
DateTime dt = (DateTime)field;
bson.Add(dt.ToUniversalTime());
break;
case JTokenType.Integer:
bson.Add((int)field);
break;
case JTokenType.Float:
bson.Add((float)field);
break;
case JTokenType.Object:
BsonDocument nestedDoc = new BsonDocument();
Parse((JObject)field, ref nestedDoc);
bson.Add(nestedDoc);
break;
}
}
return bson;
}
这是我编写的一些简单测试代码:
ModelUser user = new ModelUser();
ControllerApp app = new ControllerApp();
ControllerApp.Instance.User = user;
JObject req = new JObject();
req["first"] = "First";
req["last"] = "Last";
req["usertype"] = "parent";
req["pw"] = "q345n3452345n2345";
req["array"] = JArray.Parse("[ '1', '2', '3' ]");
req["dateTest"] = DateTime.UtcNow;
req["profile"] = new JObject();
req["profile"]["name"] = new JObject();
req["profile"]["name"]["first"] = "testUpdateFirst";
BsonDocument bd;
bd = user.ParseUpdateRequest(req);
string s = bd.ToJson();
答案 3 :(得分:0)
在ASP.net core 3.1中,您可以使用JsonPatchDocument并在mongodb中进行替换
JsonPatch in ASP.NET Core web API
[HttpPatch]
public IActionResult JsonPatchWithModelState(
[FromBody] JsonPatchDocument<Customer> patchDoc)
{
if (patchDoc != null)
{
var customer = CreateCustomer();
patchDoc.ApplyTo(customer, ModelState);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return new ObjectResult(customer);
}
else
{
return BadRequest(ModelState);
}
}
答案 4 :(得分:-1)
包含对象的数组将失败:
"array": [{"test": "value"}]
将产生{array.test[0] : "value"}
,但是mongodb期望{array.test.0 : "value"}
。